Cypher
Cypher

Reputation: 2687

How to cause a ComboBox EventHandler to be triggered when programmatically selecting items?

The ComboBox control has a method called setOnAction. This method takes in an EventHandler that is called as described by the documentation:

The ComboBox action, which is invoked whenever the ComboBox value property is changed. This may be due to the value property being programmatically changed, when the user selects an item in a popup list or dialog, or, in the case of editable ComboBoxes, it may be when the user provides their own input (be that via a TextField or some other input mechanism.

When a Stage first loads, I don't want the ComboBox to default to an empty value, I want it to automatically select the first option in the ComboBox (if it has one). The getSelectionModel().selectFirst() methods does change the selection of the ComboBox, but it for some reason does not trigger the EventHandler. However, the EventHandler for a button that calls the exact same methods will cause the EventHandler to trigger. What am I doing wrong?

Here is a brief test case that shows this behavior using JDK 8u40:

import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;

public class Test extends Application {

    public void start(Stage stage) throws Exception {
        HBox pane = new HBox();
        ComboBox<String> comboBox = new ComboBox<>();
        comboBox.getItems().add("Hello");
        comboBox.getItems().add("World");
        comboBox.setOnAction((e) -> {
             System.out.println(comboBox.getSelectionModel().getSelectedItem());
        });
        Button button = new Button("Select First");
        button.setOnAction((e) -> {
            comboBox.getSelectionModel().selectFirst();
        });

        comboBox.getSelectionModel().selectFirst();

        pane.getChildren().add(comboBox);
        pane.getChildren().add(button);
        Scene scene = new Scene(pane);
        stage.setScene(scene);
        stage.show();
    }
}

Upvotes: 4

Views: 13021

Answers (1)

Cypher
Cypher

Reputation: 2687

I don't entirely understand why this is necessary, but in order for the EventHandler passed to the setOnAction() method to trigger for the ComboBox control, the Stage must first be shown with the show() method.

import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;

public class Test extends Application {

    public void start(Stage stage) throws Exception {
        HBox pane = new HBox();
        ComboBox<String> comboBox = new ComboBox<>();
        comboBox.getItems().add("Hello");
        comboBox.getItems().add("World");
        comboBox.setOnAction((e) -> {
             System.out.println(comboBox.getSelectionModel().getSelectedItem());
        });
        Button button = new Button("Select First");
        button.setOnAction((e) -> {
            comboBox.getSelectionModel().selectFirst();
            System.out.println("The button did it!");
        });

        button.fire();

        pane.getChildren().add(comboBox);
        pane.getChildren().add(button);
        Scene scene = new Scene(pane);
        stage.setScene(scene);
        stage.show();

        comboBox.getSelectionModel().selectFirst();
    }
}

This doesn't seem to be entirely true for all controls. In the above example, calling the fire() method on the button will trigger the EventHandler even before the stage is shown.

Upvotes: 6

Related Questions