JavaFX - ColorChooser

22.03.2013

How to get a list of all JavaFX color names which are pre-defined in the class Color?

The class javafx.scene.paint.Color in JavaFX has a lot of pre-defined static color names. The usage is very simple, e.g. Color.BLUE. But how do you get a list of all these color names which are defined in the class Color? This article describes a way which uses the Java Reflection API to create a list with all these color names.

Additionally the article shows the basic usage of the GridLayout. Not a complex layout. A very simple one with four columns and four rows. But I think that the reader gets an impression how to use it.

As example I implemented a little ColorChooser with a GridPane layout. The GridPane contains some controls, so the user can select one color from a ComboBox which contains all colors of the class Color. After a color name was choosen the user can see the color in a Rectangle below. Also the HEX value of the color is displayed.

The following screenshots show the simple demo application. On the right hand side the Grid lines are visible. (I think this is a very useful feature! You can find the flag for this in the source code below.)

The important part of the application is the method getJavaFXColorMap(). This function creates a Map with color names and Color objects. The HashMap contains all colors which are defined with public static in the class Color.

/**
 * Return a Map with all all defined colors in JavaFX. The key is the static
 * name of color and the value contains an instance of a Color object.
 */
public Map<String, Color> getJavaFXColorMap() {
    Field[] declaredFields = Color.class.getDeclaredFields();
    Map<String, Color> colors = new HashMap<>();
    for (Field field : declaredFields) {
        if (Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers())) {
            try {
                colors.put(field.getName(), (Color)field.get(null));
            } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
                Logger.getLogger(JavaFXColorChooser.class.getName()).log(Level.SEVERE, null, ex);
            } 
        }
    }
    return colors;
}

First all declaredFields of the class Color are determined (Line: 6). For every Field the if-statement checks, if the field is static and public. If the condition is true the field is a variable of the Color class (e.g. public static final Color BLACK;).

Now the color name can be determined by calling field.getName() (e.g. the return value is BLACK). Additionally you want an instance of the class Color (Normally you call Color.BLACK to get such an object.). This can also be achieved by using thr Java Reflection API. You have to call the method get() of the Variable field with the value null. This returns an instance of the class Color with the desired color.

The rest of the source code creates the Scene for the application.

package org.hameister.javafx.colorchooser;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**
 * JavaFXColorChooser.
 * @author hameister
 */
public class JavaFXColorChooser extends Application {

    private static final int COL1 = 0;
    private static final int COL2 = 1;
    private static final int COL3 = 2;
    private static final int ROW1 = 0;
    private static final int ROW2 = 1;
    private static final int ROW3 = 2;
    private static final int ROW4 = 3;
    private static final int SPAN1 = 1;
    private static final int SPAN2 = 2;
    private static final int SPAN3 = 3;
    private static final int SPAN4 = 4;

    private Map<String, Color> colorMap = getJavaFXColorMap();
    private Rectangle rectangle;
    private Text hexValue;
    
    @Override
    public void start(Stage primaryStage) {
        GridPane grid = new GridPane();
        grid.setHgap(10);
        grid.setVgap(30);
        grid.setPadding(new Insets(10, 20, 10, 20));
        // Show the Grid lines. 
        //grid.setGridLinesVisible(true);

        ImageView pencil = new ImageView(new Image(JavaFXColorChooser.class.getResourceAsStream("StiftSmall.png")));
        grid.add(pencil, COL1, ROW1);

        Text colorChooserTitle = new Text("Color Chooser");
        colorChooserTitle.setFont(Font.font("Arial", FontWeight.BOLD, 36));
        grid.add(colorChooserTitle, COL2, ROW1, SPAN3, SPAN1);

        Text colorByName = new Text("Select Color by Name:");
        colorByName.setFont(Font.font("Arial", FontWeight.NORMAL, 16));
        grid.add(colorByName, COL1, ROW2, SPAN2, SPAN1);

        // Sort the colors
        ObservableList<String> colors = FXCollections.observableArrayList(colorMap.keySet());
        FXCollections.sort(colors);
        
        ComboBox box = new ComboBox(colors);
        box.getSelectionModel().selectFirst();
        box.valueProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue ov, String oldColor, String newColor) {
                rectangle.setFill(colorMap.get(newColor));
                hexValue.setText((colorMap.get(newColor).toString()));
            }
        });
        grid.add(box, COL3, ROW2, SPAN2, SPAN1);

        rectangle = new Rectangle(400, 40);
        grid.add(rectangle, COL1, ROW3, SPAN4, SPAN1);
        rectangle.setFill(colorMap.get(box.getSelectionModel().getSelectedItem().toString()));
        rectangle.setStroke(Color.BLACK);
        
        Text hex = new Text("Hex value:");
        hex.setFont(Font.font("Arial", FontWeight.BOLD, 16));
        grid.add(hex, COL2, ROW4);

        hexValue = new Text(colorMap.get(box.getSelectionModel().getSelectedItem().toString()).toString());
        hexValue.setFont(Font.font("Arial", FontWeight.NORMAL, 16));
        grid.add(hexValue, COL3, ROW4);
        
        Scene scene = new Scene(grid, 440, 280);

        primaryStage.setTitle("Color Chooser");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

A GridPane with four columns and four rows is used to place an ImageView, some Text labels, a ComboBox and a Rectangle for the Color. The grid of the application can be displayed by changing the flag in line 56. The result can be seen on the right screenshot above.

The ComboBox uses a ChangeListener to update the Rectangle and the Text for the hexValue.

Further Informations

On this Oracle page you find a great article about Layouts: Using Built-in Layout Panes