ComboBox

JavaFX Combobox Example

This is a JavaFX Combobox example. ComboBox is used to let a user select an item from a list of items. It is highly customizable. If you want to create a custom control that will allow users to select an item from a pop-up list, you need to inherit your control from the ComboBoxBase class.
 
 
 
 
 
 
 

 
The following table shows an overview of the whole tutorial:

The following examples uses Java SE 7 and JavaFX 2.2.

1. Introduction

1.1 The Code

FxComboBoxExample1.java

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
 
public class FxComboBoxExample1 extends Application
{
    // Declaring Labels for messages
    Label userSelectionMsgLbl = new Label("Your selection: ");
    Label userSelectionDataLbl = new Label("");
    Label itemChangeLbl = new Label("Item Changed: ");
    Label indexChangeLbl = new Label("Index Changed: ");
 
    public static void main(String[] args)
    {
        Application.launch(args);
    }
 
    @Override
    public void start(Stage stage)
    {
        // Create the Label
        Label monthsLbl = new Label("Month:");
 
        // Create the ComboBox
        final ComboBox<String> months = new ComboBox<>();
        // Add the Months to the ComboBox
        months.getItems().addAll("January", "February", "March", "April", "May", "June",
                "July""August", "September", "October", "November", "December");
        // Set the Limit of visible months to 5
        months.setVisibleRowCount(5);
 
        // Update the message Label when the selected item changes
        months.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>()
        {
            public void changed(ObservableValue<? extends String> ov,
                    final String oldvalue, final String newvalue)
            {
                monthChanged(ov, oldvalue, newvalue);
        }});
 
        // Update the message Label when the index changes
        months.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>()
        {
            public void changed(ObservableValue<? extends Number> ov,
                    final Number oldvalue, final Number newvalue)
            {
                indexChanged(ov, oldvalue, newvalue);
            }
        });
 
        // Update the message Label when the value changes
        months.setOnAction(new EventHandler<ActionEvent>()
        {
            @Override public void handle(ActionEvent e)
            {
                valueChanged(months);
            }
        });
 
        // Create the HBox for the Months
        HBox monthBox = new HBox();
        // add the Label and the ComboBox to the HBox
        monthBox.getChildren().addAll(monthsLbl, months);
 
        // Create the HBox for the Selection
        HBox selectionBox = new HBox();
        // Add the Labels to the HBox
        selectionBox.getChildren().addAll(userSelectionMsgLbl, userSelectionDataLbl);
 
        // Create the VBox
        VBox root = new VBox();
        // Add the details to the VBox
        root.getChildren().addAll(monthBox, selectionBox, itemChangeLbl, indexChangeLbl);
        // Set the vertical spacing between children to 10px
        root.setSpacing(10);
 
        // Set the Style-properties of the VBox
        root.setStyle("-fx-padding: 10;" +
                "-fx-border-style: solid inside;" +
                "-fx-border-width: 2;" +
                "-fx-border-insets: 5;" +
                "-fx-border-radius: 5;" +
                "-fx-border-color: blue;");
 
        // Create the Scene
        Scene scene = new Scene(root,300,200);
        // Add the scene to the Stage
        stage.setScene(scene);
        // Set the title of the Stage
        stage.setTitle("Using the ComboBox Control");
        // Display the Stage
        stage.show();
    }
 
    // Method to display the selected Month
    public void valueChanged(ComboBox<String> list)
    {
        String month = list.getValue();
        userSelectionDataLbl.setText(month);
    }
 
    // Method to display the Data, which has been changed
    public void monthChanged(ObservableValue<? extends String> observable,String oldValue,String newValue)
    {
        String oldText = oldValue == null ? "null" : oldValue.toString();
        String newText = newValue == null ? "null" : newValue.toString();
 
        itemChangeLbl.setText("Itemchanged: old = " + oldText + ", new = " + newText + "\n");
    }
 
    // Method to display the Index, which has been changed
    public void indexChanged(ObservableValue<? extends Number> observable,Number oldValue,Number newValue)
    {
        indexChangeLbl.setText( "Indexchanged: old = " + oldValue + ", new = " + newValue + "\n");
    }
}

The items list in a ComboBox may comprise any type of objects. ComboBox is a parameterized class. The parameter type is the type of the items in the list. You can specify the list items while creating a ComboBox, as in the following code snippet:

1
2
3
4
5
// Create the ComboBox
final ComboBox<String> months = new ComboBox<>();
// Add the Months to the ComboBox
months.getItems().addAll("January", "February", "March", "April", "May", "June",
        "July""August", "September", "October", "November", "December");

In our case we will use the String class as the parameter type.

1.2 Detecting Value Change in ComboBox

Detecting an item change in a noneditable combo box is easily performed by adding a ChangeListener to the selectedIndex or selectedItem property of its selection model.

You can still use a ChangeListener for the selectedItem property to detect when the value in an editable combo box changes by selecting from the items list or entering a new value. When you enter a new value, the selectedIndex property does not change because the entered value does not exist in the items list.

The following code snippet shows an example of a ChangeListener for the value and the index of an item in the list:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
// Update the message Label when the selected item changes
months.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>()
{
    public void changed(ObservableValue<? extends String> ov,
            final String oldvalue, final String newvalue)
    {
        monthChanged(ov, oldvalue, newvalue);
}});
 
// Update the message Label when the index changes
months.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>()
{
    public void changed(ObservableValue<? extends Number> ov,
            final Number oldvalue, final Number newvalue)
    {
        indexChanged(ov, oldvalue, newvalue);
    }
});

Sometimes you want to perform an action when the value in a combo box changes. You can do so by adding an ActionEvent handler, which is fired when the value changes by any means. You would do this by setting it programmatically, selecting from items list, or entering a new value, as in the following code snippet:

1
2
3
4
5
6
7
8
// Update the message Label when the value changes
months.setOnAction(new EventHandler<ActionEvent>()
{
    @Override public void handle(ActionEvent e)
    {
        valueChanged(months);
    }
});

1.3 Customizing the Height of Pop-up List

By default, ComboBox shows only ten items in the pop-up list. If the number of items is more than ten, the pop-up list shows a scrollbar. If the number of items is less than ten, the height of the pop-up list is shortened to show only the available items. The visibleRowCount property of the ComboBox controls how many rows are visible in the pop-up list, as in the following example:

1
2
// Set the Limit of visible months to 5
months.setVisibleRowCount(5);

1.4 The GUI

After starting the program, we can choose a given month from the item list in the ComboBox:

Selecting a Month from the List in the ComboBox
Selecting a Month from the List in the ComboBox

After choosing a month, the selected value and all messages from the ChangeListener and EventHandler are shown:

The GUI after Selection of the Month
The GUI after Selection of the Month

2. Using Domain Objects in Editable ComboBox

2.1 The Person Class

The Person-Class contains only the attributes first name and last name of a Person. The class also supports a Constructor, Getters and Setters for each attribute and a toString Method

Person.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Person
{
    // Declaring the attributes
    private String firstName;
    private String lastName;
 
    public Person(String firstName, String lastName)
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }
 
    public String getFirstName()
    {
        return firstName;
    }
 
    public void setFirstName(String firstName)
    {
        this.firstName = firstName;
    }
 
    public String getLastName()
    {
        return lastName;
    }
 
    public void setLastName(String lastName)
    {
        this.lastName = lastName;
    }
 
    @Override
    public String toString()
    {
        return "Person [firstName=" + firstName + ", lastName=" + lastName + "]";
    }
}

2.2 The PersonConverter Class

PersonConverter.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import javafx.util.StringConverter;
 
public class PersonConverter extends StringConverter<Person>
{
    // Method to convert a Person-Object to a String
    @Override
    public String toString(Person person)
    {
        return person == null? null : person.getLastName() + ", " + person.getFirstName();
    }
 
    // Method to convert a String to a Person-Object
    @Override
    public Person fromString(String string)
    {
        Person person = null;
 
        if (string == null)
        {
            return person;
        }
 
        int commaIndex = string.indexOf(",");
 
        if (commaIndex == -1)
        {
            person = new Person(string, null);
        }
        else
        {
            String firstName = string.substring(commaIndex + 2);
            String lastName = string.substring(0, commaIndex);
            person = new Person(firstName, lastName);
        }
 
        return person;
    }
}

In an editable ComboBox<T> where T is something other than String, you must set the converter property to a valid StringConverter<T>. Its toString(T object) method is used to convert the item object to a string to show it in the pop-up list. Its fromString(String s) method is called to convert the entered string to an item object. The value property is updated with the item object converted from the entered string. If the entered string cannot be converted to an item object, the value property is not updated

2.3 The Code

FxComboBoxExample2.java

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import java.util.ArrayList;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
 
public class FxComboBoxExample2 extends Application
{
    // Declaring Labels for messages
    Label userSelectionMsgLbl = new Label("Your selection: ");
    Label userSelectionDataLbl = new Label("");
    Label itemChangeLbl = new Label("Item Changed: ");
    Label indexChangeLbl = new Label("Index Changed: ");
 
    public static void main(String[] args)
    {
        Application.launch(args);
    }
 
    @Override
    public void start(Stage stage)
    {
        // Create the Label
        Label personLbl = new Label("Select/Enter Person:");
 
        // Create the ComboBox
        final ComboBox<Person> persons = new ComboBox<>();
        // Add the Persons to the ComboBox
        persons.getItems().addAll(createPersonList());
        // Set Converter to the ComboBox
        persons.setConverter(new PersonConverter());
 
        // Update the message Label when the selected item changes
        persons.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Person>()
        {
            public void changed(ObservableValue<? extends Person> ov,
                    final Person oldvalue, final Person newvalue)
            {
                personChanged(ov, oldvalue, newvalue);
            }
        });
 
        // Update the message Label when the index changes
        persons.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>()
        {
            public void changed(ObservableValue<? extends Number> ov,
                    final Number oldvalue, final Number newvalue)
            {
                indexChanged(ov, oldvalue, newvalue);
        }});
 
        // Update the message Label when the value changes
        persons.setOnAction(new EventHandler<ActionEvent>()
        {
            @Override public void handle(ActionEvent e)
            {
                valueChanged(persons);
            }
        });
 
        // create the HBox for the Persons
        HBox personBox = new HBox();
        // Add the Label and the ComboBox to the HBox
        personBox.getChildren().addAll(personLbl, persons);
 
        // Create the HBox for User Selection
        HBox selectionBox = new HBox();
        // Add the Labels to the HBox
        selectionBox.getChildren().addAll(userSelectionMsgLbl, userSelectionDataLbl);
 
        // create the VBox
        VBox root = new VBox();
        // Add the children to the VBox
        root.getChildren().addAll(personBox, selectionBox, itemChangeLbl, indexChangeLbl);
        // Set the vertical spacing between children to 10px
        root.setSpacing(10);
 
        // Set the Style-properties of the VBox
        root.setStyle("-fx-padding: 10;" +
            "-fx-border-style: solid inside;" +
            "-fx-border-width: 2;" +
            "-fx-border-insets: 5;" +
            "-fx-border-radius: 5;" +
            "-fx-border-color: blue;");
 
        // Create the Scene
        Scene scene = new Scene(root, 500, 200);
        // Add the scene to the Stage
        stage.setScene(scene);
        // Set the title of the Stage
        stage.setTitle("Using StringConverter in ComboBox");
        // Display the Stage
        stage.show();
    }
 
    // Helper-Method to create an ArrayList of Persons
    private ArrayList<Person> createPersonList()
    {
        ArrayList<Person> persons = new ArrayList<Person>();
 
        persons.add(new Person("Donna", "Duncan"));
        persons.add(new Person("Layne", "Estes"));
        persons.add(new Person("John", "Jacobs"));
        persons.add(new Person("Mason", "Boyd"));
        persons.add(new Person("Harry", "Eastwood"));
 
        return persons;
    }
 
    // Method to display the selected Person
    public void valueChanged(ComboBox<Person> list)
    {
        Person p = list.getValue();
        String name = p.getLastName() + ", " + p.getFirstName();
        userSelectionDataLbl.setText(name);
    }
 
    // Method to display the Data, which has been changed
    public void personChanged(ObservableValue<? extends Person> observable,Person oldValue,Person newValue)
    {
        String oldText = oldValue == null ? "null" : oldValue.toString();
        String newText = newValue == null ? "null" : newValue.toString();
 
        itemChangeLbl.setText("Itemchanged: old = " + oldText + ", new = " + newText + "\n");
    }
 
    // Method to display the Index, which has been changed
    public void indexChanged(ObservableValue<? extends Number> observable,Number oldValue,Number newValue)
    {
        indexChangeLbl.setText( "Indexchanged: old = " + oldValue + ", new = " + newValue + "\n");
    }
}

The above example and also the following code snippet shows how to use a StringConverter in a combo box, which uses domain objects in its items list. The ComboBox uses Person objects. The program adds a ChangeListener to the selectedItem and selectedIndex properties of the selection model to track the selection change. An ActionEvent handler for the ComboBox is used to keep the values in the combo box and the text in the Label in sync.

The PersonConverter class is used as the StringConverter. The following code snippet shows, how to set the StringConverter to the ComboBox:

1
2
3
4
5
6
// Create the ComboBox
final ComboBox<Person> persons = new ComboBox<>();
// Add the Persons to the ComboBox
persons.getItems().addAll(createPersonList());
// Set Converter to the ComboBox
persons.setConverter(new PersonConverter());

2.4 The GUI

The following GUI shows an example of using the Person class and it´s corresponding StringConverter to choose a person from the list:

Selection of a Person from the List in the ComboBox
Selection of a Person from the List in the ComboBox

3. Using Nodes as Items in ComboBox

In our next example we will use a cell factory to display nodes in the button area and the pop-up area of a combo box.

A combo box has two areas:

  • Button area to display the selected item
  • Pop-up area to display the items list

Both areas use a ListCell to display items. A ListCell is a Cell. A Cell is a Labeled control to display some form of content that may have text, a graphic, or both. The pop-up area is a ListView that contains an instance of ListCell for each item in the list.

3.1 The ShapeCell Class

ShapeCell.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import javafx.scene.control.ListCell;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.scene.text.Text;
 
public class ShapeCell extends ListCell<String>
{
    @Override
    public void updateItem(String item, boolean empty)
    {
        super.updateItem(item, empty);
 
        if (empty)
        {
            setText(null);
            setGraphic(null);
        }
        else
        {
            setText(item);
            Shape shape = this.getShape(item);
            setGraphic(shape);
        }
    }
 
    public Shape getShape(String shapeType)
    {
        Shape shape = null;
 
        switch (shapeType.toLowerCase())
        {
            case "line":
                shape = new Line(0, 10, 20, 10);
                break;
            case "rectangle":
                shape = new Rectangle(0, 0, 20, 20);
                break;
            case "circle":
                shape = new Circle(20, 20, 10);
                break;
            case "Text":
                shape = new Text(10, 50, "This is a Text");
                break;
            default:
                shape = null;
        }
 
        return shape;
    }
}

The above code declares a ShapeCell class, which inherits from the ListCell<String> class. You need to update its content in its updateItem() method, which is automatically called. The method receives the item, which in this case is String, and a boolean argument indicating whether the cell is empty. Inside the method, you call the method in the superclass first. You derive a shape from the string argument and set the text and graphic in the cell. The shape is set as the graphic. The getShape() method returns a Shape from a String.

3.2 The Code

FxComboBoxExample3.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
 
public class FxComboBoxExample3  extends Application
{
    public static void main(String[] args)
    {
        Application.launch(args);
    }
 
    @Override
    public void start(Stage stage)
    {
        // Create the Label
        Label shapeLbl = new Label("Shape:");
 
        // Create the ComboBox
        ComboBox<String> shapes = new ComboBox<>();
        // Add the Shapes to the ComboBox
        shapes.getItems().addAll("Line", "Rectangle", "Circle", "Text");
 
        // Set the CellFactory property
        shapes.setCellFactory(new ShapeCellFactory());
        // Set the ButtonCell property
        shapes.setButtonCell(new ShapeCell());
 
        // CReate the HBox
        HBox root = new HBox();
        // Add the children to the HBox
        root.getChildren().addAll(shapeLbl, shapes);
 
        // Set the Style-properties of the HBox
        root.setStyle("-fx-padding: 10;" +
            "-fx-border-style: solid inside;" +
            "-fx-border-width: 2;" +
            "-fx-border-insets: 5;" +
            "-fx-border-radius: 5;" +
            "-fx-border-color: blue;");
 
        // Create the Scene
        Scene scene = new Scene(root,300,200);
        // Add the scene to the Stage
        stage.setScene(scene);
        // Set the title of the Stage
        stage.setTitle("Using CellFactory in ComboBox");
        // Display the Stage
        stage.show();
    }
 
}

Elements in the items list of a combo box can be of any type, including Node type. It is not recommended to add instances of the Node class directly to the items list. When nodes are used as items, they are added as the graphic to the cells. Scene graphics need to follow the rule that a node cannot be displayed in two places at the same time. That is, a node must be inside one container at a time. When a node from the items list is selected, the node is removed from the pop-up ListView cell and added to the button area. When the pop-up is displayed again, the selected node is not shown in the list as it is already showing in the button area. To avoid this inconsistency in display, avoid using nodes directly as items in a combo box.

3.3 Using a Cell Factory in ComboBox

ShapeCellFactory.java

01
02
03
04
05
06
07
08
09
10
11
12
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;
 
public class ShapeCellFactory implements Callback<ListView<String>, ListCell<String>>
{
    @Override
    public ListCell<String> call(ListView<String> listview)
    {
        return new ShapeCell();
    }
}

The ComboBox class contains a cellFactory property, which is declared as follows:

1
public ObjectProperty<Callback<ListView<T>, ListCell<T>>> cellFactory;

Callback is an interface in the javafx.util package. It has a call() method that takes an argument of type P and returns and object of type R, as in the following code:

1
2
3
4
5
6
7
8
public class ShapeCellFactory implements Callback<ListView<String>, ListCell<String>>
{
    @Override
    public ListCell<String> call(ListView<String> listview)
    {
        return new ShapeCell();
    }
}

The declaration of the cellFactory property states that it stores a Callback object whose call() method receives a ListView<String> and returns a ListCell<String>.

The following code snippet shows how to use a custom cell factory and button cell in a combo box:

1
2
// Set the CellFactory property
shapes.setCellFactory(new ShapeCellFactory());

3.4 The GUI

After launching the application, you make your selection:

Selecting a Shape from the List of the ComboBox
Selecting a Shape from the List of the ComboBox

After choosing a shape, the Shape itself and the corresponding Text is visible:

The GUI after Selecting a specific Shape
The GUI after Selecting a specific Shape

4. Download Java Source Code

This was an example of javafx.scene.control.ComboBox

Download
You can download the full source code of this example here: JavaFxComboBoxExample.zip

Andreas Pomarolli

Andreas has graduated from Computer Science and Bioinformatics at the University of Linz. During his studies he has been involved with a large number of research projects ranging from software engineering to data engineering and at least web engineering. His scientific focus includes the areas of software engineering, data engineering, web engineering and project management. He currently works as a software engineer in the IT sector where he is mainly involved with projects based on Java, Databases and Web Technologies.
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Carlos
4 years ago

Thanks a lot:

Back to top button