Documentation



JavaFX: Working with JavaFX UI Components

16 Combo Box

This chapter explains how to use combo boxes in your JavaFX application. It discusses editable and uneditable combo boxes, teaches you how to track changes in the editable combo boxes and handle events on them, and explains how to use cell factories to alter the default implementation of a combo box.

A combo box is a typical element of a user interface that enables users to choose one of several options. A combo box is helpful when the number of items to show exceeds some limit, because it can add scrolling to the drop down list, unlike a choice box. If the number of items does not exceed a certain limit, developers can decide whether a combo box or a choice box better suits their needs.

You can create a combo box in the JavaFX application by using the ComboBox class of the JavaFX API. Figure 16-1 shows an application with two combo boxes.

Figure 16-1 Application with Two Combo Boxes

Description of Figure 16-1 follows
Description of "Figure 16-1 Application with Two Combo Boxes"

Creating Combo Boxes

When creating a combo box, you must instantiate the ComboBox class and define the items as an observable list, just like other UI controls such as ChoiceBox, ListView, and TableView. Example 16-1 sets the items within a constructor.

Example 16-1 Creating a Combo Box with an Observable List

ObservableList<String> options = 
    FXCollections.observableArrayList(
        "Option 1",
        "Option 2",
        "Option 3"
    );
final ComboBox comboBox = new ComboBox(options);

Another possibility is to create a combo box by using an empty constructor and call the setItems method on it, as follows: comboBox.setItems(options);

When the combo box is added to the application scene, it appears in the user interface as shown in Figure 16-2.

Figure 16-2 Combo Box with Three Items

Description of Figure 16-2 follows
Description of "Figure 16-2 Combo Box with Three Items"

At any time, you can supplement the list of items with new values. Example 16-2 implements this task by adding three more items to the comboBox control.

Example 16-2 Adding Items to a Combo Box

comboBox.getItems().addAll(
    "Option 4",
    "Option 5",
    "Option 6"
);

The ComboBox class provides handy properties and methods to use with combo boxes.

You can use the setValue method to specify the item selected in the combo box. When you call the setValue method on the ComboBox object, the selected item of the selectionModel property changes to this value even if the value is not in the combo box items list. If the items list then changes to include this value, the corresponding item becomes selected.

Similarly, you can obtain the value of the selected item by calling the getValue method. When a user selects an item, the selected item of the selectionModel property and the combo box value property are both updated to the new value.

You can also restrict the number of visible rows in the ComboBox drop down list when it is displayed. The following code line enables the display of three items for the comboBox control: comboBox.setVisibleRowCount(3) As the result of calling this method, the number of visible rows is limited to three, and a scroll bar appears (as shown in Figure 16-3).

Figure 16-3 Setting the Number of Visible Rows for a Combo Box

Description of Figure 16-3 follows
Description of "Figure 16-3 Setting the Number of Visible Rows for a Combo Box"

Although the ComboBox class has a generic notation and enables users to populate it with items of various types, do not use Node (or any subclass) as the type. Because the scene graph concept implies that only one Node object can be in one place of the application scene, the selected item is removed from the ComboBox list of items. When the selection changes, the previously selected item returns to the list and the new selection is removed. To prevent this situation, use the cell factory mechanism and the solution described in the API documentation. The cell factory mechanism is particularly helpful when you need to change the initial behavior or appearance of the ComboBox object.

The ComboBoxSample application is designed to illustrate how to use combo boxes in a typical email interface. Example 16-3 creates a such an interface, in which two combo boxes are used to select the email recipient and the priority of the message.

Example 16-3 Creating Combo Boxes and Adding Them to the Scene

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
 
public class ComboBoxSample extends Application {
    public static void main(String[] args) {
        launch(args);
    }
        
    final Button button = new Button ("Send");
    final Label notification = new Label ();
    final TextField subject = new TextField("");
    final TextArea text = new TextArea ("");
    
    String address = " ";
    
    @Override public void start(Stage stage) {
        stage.setTitle("ComboBoxSample");
        Scene scene = new Scene(new Group(), 500, 270);
        
        final ComboBox emailComboBox = new ComboBox();
        emailComboBox.getItems().addAll(
            "jacob.smith@example.com",
            "isabella.johnson@example.com",
            "ethan.williams@example.com",
            "emma.jones@example.com",
            "michael.brown@example.com"  
        );
        
        final ComboBox priorityComboBox = new ComboBox();
        priorityComboBox.getItems().addAll(
            "Highest",
            "High",
            "Normal",
            "Low",
            "Lowest" 
        );   

        priorityComboBox.setValue("Normal");
        
        GridPane grid = new GridPane();
        grid.setVgap(4);
        grid.setHgap(10);
        grid.setPadding(new Insets(5, 5, 5, 5));
        grid.add(new Label("To: "), 0, 0);
        grid.add(emailComboBox, 1, 0);
        grid.add(new Label("Priority: "), 2, 0);
        grid.add(priorityComboBox, 3, 0);
        grid.add(new Label("Subject: "), 0, 1);
        grid.add(subject, 1, 1, 3, 1);            
        grid.add(text, 0, 2, 4, 1);
        grid.add(button, 0, 3);
        grid.add (notification, 1, 3, 3, 1);
        
        Group root = (Group)scene.getRoot();
        root.getChildren().add(grid);
        stage.setScene(scene);
        stage.show();
    }    
}

Both combo boxes in Example 16-3 use the getItems and addAll methods to add items. When you compile and run this code, it produces the application window shown in Figure 16-4.

Figure 16-4 Email Recipient and Priority Combo Boxes

Description of Figure 16-4 follows
Description of "Figure 16-4 Email Recipient and Priority Combo Boxes"

Editable Combo Boxes

Typically, email client applications enable users to both select recipients from the address book and type a new address. An editable combo box perfectly fits this task. Use the setEditable(true) method of the ComboBox class to make a combo box editable. With the setPromptText method, you can specify the text to appear in the combo box editing area when no selection is performed. Examine the modified code of the application in Example 16-4. The bold lines are the additions made to Example 16-3.

Example 16-4 Processing Newly Typed Values in an Editable Combo Box

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
 
public class ComboBoxSample extends Application {
        public static void main(String[] args) {
        launch(args);
    }
    
    final Button button = new Button ("Send");
    final Label notification = new Label ();
    final TextField subject = new TextField("");
    final TextArea text = new TextArea ("");
    
    String address = " ";
    
    @Override public void start(Stage stage) {
        stage.setTitle("ComboBoxSample");
        Scene scene = new Scene(new Group(), 500, 270);
        
        final ComboBox emailComboBox = new ComboBox();
        emailComboBox.getItems().addAll(
            "jacob.smith@example.com",
            "isabella.johnson@example.com",
            "ethan.williams@example.com",
            "emma.jones@example.com",
            "michael.brown@example.com"  
        );
        emailComboBox.setPromptText("Email address");
        emailComboBox.setEditable(true);        
        emailComboBox.setOnAction((Event ev) -> {
            address = 
                emailComboBox.getSelectionModel().getSelectedItem().toString();    
        });
        
        final ComboBox priorityComboBox = new ComboBox();
        priorityComboBox.getItems().addAll(
            "Highest",
            "High",
            "Normal",
            "Low",
            "Lowest" 
        );   

        priorityComboBox.setValue("Normal");
     
        button.setOnAction((ActionEvent e) -> {
            if (emailComboBox.getValue() != null && 
                    !emailComboBox.getValue().toString().isEmpty()){
                notification.setText("Your message was successfully sent"
                        + " to " + address);
                emailComboBox.setValue(null);
                if (priorityComboBox.getValue() != null &&
                        !priorityComboBox.getValue().toString().isEmpty()){
                    priorityComboBox.setValue(null);
                }
                subject.clear();
                text.clear();
            }
            else {
                notification.setText("You have not selected a recipient!");
            }
        });

        GridPane grid = new GridPane();
        grid.setVgap(4);
        grid.setHgap(10);
        grid.setPadding(new Insets(5, 5, 5, 5));
        grid.add(new Label("To: "), 0, 0);
        grid.add(emailComboBox, 1, 0);
        grid.add(new Label("Priority: "), 2, 0);
        grid.add(priorityComboBox, 3, 0);
        grid.add(new Label("Subject: "), 0, 1);
        grid.add(subject, 1, 1, 3, 1);            
        grid.add(text, 0, 2, 4, 1);
        grid.add(button, 0, 3);
        grid.add (notification, 1, 3, 3, 1);
        
        Group root = (Group)scene.getRoot();
        root.getChildren().add(grid);
        stage.setScene(scene);
        stage.show();
    }
}

Besides the ability to edit emailComboBox, this code fragment implements event handling for this control. The newly typed or selected value is stored in the address variable. When users press the Send button, the notification containing the email address is shown.

Figure 16-5 captures the moment when a user is editing the email address of Jacob Smith and changing it to greg.smith@example.com.

Figure 16-5 Editing an Email Address

Description of Figure 16-5 follows
Description of "Figure 16-5 Editing an Email Address"

When the Send button is pressed, all the controls return to their default states. The clear methods are called on the TextField and TextArea objects, and the null value is set for the combo box selected items. Figure 16-6 shows the moment after the Send button is pressed.

Figure 16-6 User Interface After the Send Button Is Pressed

Description of Figure 16-6 follows
Description of "Figure 16-6 User Interface After the Send Button Is Pressed"

Applying Cell Factories to Combo Boxes

You can use the cell factory mechanism to alter the default behavior or appearance of a combo box. Example 16-5 creates a cell factory and applies it to the priority combo box to highlight priority types with special colors.

Example 16-5 Implementing a Cell Factory for the Priority Combo Box

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Callback;
 
public class ComboBoxSample extends Application {
        public static void main(String[] args) {
        launch(args);
    }
    
    final Button button = new Button ("Send");
    final Label notification = new Label ();
    final TextField subject = new TextField("");
    final TextArea text = new TextArea ("");
    
    String address = " ";
    
    @Override public void start(Stage stage) {
        stage.setTitle("ComboBoxSample");
        Scene scene = new Scene(new Group(), 500, 270);
        
        final ComboBox emailComboBox = new ComboBox();
        emailComboBox.getItems().addAll(
            "jacob.smith@example.com",
            "isabella.johnson@example.com",
            "ethan.williams@example.com",
            "emma.jones@example.com",
            "michael.brown@example.com"  
        );
        emailComboBox.setPromptText("Email address");
        emailComboBox.setEditable(true);        
        emailComboBox.setOnAction((Event ev) -> {
            address = 
                emailComboBox.getSelectionModel().getSelectedItem().toString();    
        });
        
        final ComboBox priorityComboBox = new ComboBox();
        priorityComboBox.getItems().addAll(
            "Highest",
            "High",
            "Normal",
            "Low",
            "Lowest" 
        );   

        priorityComboBox.setValue("Normal");
        priorityComboBox.setCellFactory(
            new Callback<ListView<String>, ListCell<String>>() {
                @Override public ListCell<String> call(ListView<String> param) {
                    final ListCell<String> cell = new ListCell<String>() {
                        {
                            super.setPrefWidth(100);
                        }    
                        @Override public void updateItem(String item, 
                            boolean empty) {
                                super.updateItem(item, empty);
                                if (item != null) {
                                    setText(item);    
                                    if (item.contains("High")) {
                                        setTextFill(Color.RED);
                                    }
                                    else if (item.contains("Low")){
                                        setTextFill(Color.GREEN);
                                    }
                                    else {
                                        setTextFill(Color.BLACK);
                                    }
                                }
                                else {
                                    setText(null);
                                }
                            }
                };
                return cell;
            }
        });
     
        button.setOnAction((ActionEvent e) -> {
            if (emailComboBox.getValue() != null && 
                    !emailComboBox.getValue().toString().isEmpty()){
                notification.setText("Your message was successfully sent"
                        + " to " + address);
                emailComboBox.setValue(null);
                if (priorityComboBox.getValue() != null &&
                        !priorityComboBox.getValue().toString().isEmpty()){
                    priorityComboBox.setValue(null);
                }
                subject.clear();
                text.clear();
            }
            else {
                notification.setText("You have not selected a recipient!");
            }
        })
        
        GridPane grid = new GridPane();
        grid.setVgap(4);
        grid.setHgap(10);
        grid.setPadding(new Insets(5, 5, 5, 5));
        grid.add(new Label("To: "), 0, 0);
        grid.add(emailComboBox, 1, 0);
        grid.add(new Label("Priority: "), 2, 0);
        grid.add(priorityComboBox, 3, 0);
        grid.add(new Label("Subject: "), 0, 1);
        grid.add(subject, 1, 1, 3, 1);            
        grid.add(text, 0, 2, 4, 1);
        grid.add(button, 0, 3);
        grid.add (notification, 1, 3, 3, 1);
        
        Group root = (Group)scene.getRoot();
        root.getChildren().add(grid);
        stage.setScene(scene);
        stage.show();
 
    }    
}

The cell factory produces ListCell objects. Every cell is associated with a single combo box item. The width of each combo box item is set through the setPrefWidth method. The updateItem method sets the red color for the High and Highest items, green color for the Low and Lowest items, and leaves the Normal item black.

Figure 16-7 shows the items of the priority combo box after the cell factory in Example 16-5 is applied.

Figure 16-7 Modified the Priority Combo Box

Description of Figure 16-7 follows
Description of "Figure 16-7 Modified the Priority Combo Box"

You can further enhance the appearance of the ComboBox control by applying CSS styles or visual effects.

Related API Documentation 

Close Window

Table of Contents

JavaFX: Working with JavaFX UI Components

Expand | Collapse