简体   繁体   中英

Invoke a ComboBox's enter key/action event handler regardless of value property change

With an editable ComboBox , is there any way to have the ENTER key event or action event handler occur regardless of whether or not the Combobox 's value property has changed?

I essentially would like to have the same behaviour in a ComboBox 's TextField on pressing the ENTER key as it occurs for a TextField .

What I Have Tried

My initial thought was to simply use setOnAction for a ComboBox ; however, according to the documentation for it:

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.

Thus, by using setOnAction , the event handler only occurs if:

  1. The value property is changed via a change in selection from the drop down OR
  2. The value property is changed via user-input (ie: it does not occur if the user does not type anything and presses ENTER nor does it occur if the user does not change their input after the event handler has run once and they press ENTER).

Also, neither using setOnAction on the ComboBox 's TextField nor using setOnKeyPressed achieves the desired behaviour.

Below is an SSCCE to demonstrate:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class Example extends Application {

    @Override
    public void start(Stage primaryStage) {
        ComboBox<String> comboBox =
            new ComboBox<String>(
                    FXCollections.observableArrayList("XYZ", "ABC"));
        comboBox.setEditable(true);
        comboBox.setValue(comboBox.getValue());
        comboBox.setOnAction((event) -> System.out
                .println("occurs on selection changes or text changes and ENTER key"));
        comboBox.getEditor().setOnAction(
                (event) -> System.out.println("this never happens"));
        comboBox.getEditor().setOnKeyPressed((keyEvent) -> {
            if (keyEvent.getCode() == KeyCode.ENTER)
                System.out.println("this never happens either");
        });

        TextField tf = new TextField();
        tf.setOnAction((event) -> System.out.println("always happens on ENTER"));

        HBox hbox = new HBox(comboBox, tf);

        Scene scene = new Scene(hbox);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

As a general way of finding out how eventing works, you could always add an eventfilter with Event.ANY and see what happens, eg:

comboBox.getEditor().addEventFilter(Event.ANY, e -> System.out.println(e));

The event gets fired, as can be seen in the console. So what you need is to add a filter for the key code like this:

comboBox.getEditor().addEventFilter(KeyEvent.KEY_PRESSED, e -> {

    if (e.getCode() == KeyCode.ENTER) {
        System.out.println( "Enter pressed");
    }

});

Regarding your problem you can take a look at ComboBoxListViewSkin where you can see that the event is consumed.

private EventHandler<KeyEvent> textFieldKeyEventHandler = event -> {
    if (textField == null || ! getSkinnable().isEditable()) return;
    handleKeyEvent(event, true);
};

...

private void handleKeyEvent(KeyEvent ke, boolean doConsume) {
    // When the user hits the enter or F4 keys, we respond before
    // ever giving the event to the TextField.
    if (ke.getCode() == KeyCode.ENTER) {
        setTextFromTextFieldIntoComboBoxValue();

        if (doConsume) ke.consume();
    } 
    ...
}

So in short: Use an EventFilter instead of an EventHandler.

You can read more about that in the Handling JavaFX Events documentation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM