调用 ComboBox 的输入 key/action 事件处理程序,无论值 属性 更改如何

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

对于可编辑的 ComboBox,有没有办法让 ENTER 键事件或操作事件处理程序发生,而不管 Combobox 的值是否 属性变了?

我基本上希望在 ComboBoxTextField 中按下 ENTER 键时具有与 TextField.

相同的行为

我试过的

我最初的想法是简单地使用 setOnAction 作为 ComboBox;但是,根据它的文档:

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.

因此,通过使用 setOnAction,事件处理程序仅在以下情况发生:

  1. 值 属性 通过更改从 下拉或
  2. 值 属性 通过用户输入更改(即:它不会发生 如果用户不输入任何内容并按 ENTER 也不会发生 如果用户在事件处理程序 运行 之后没有更改他们的输入 一次,然后他们按 ENTER)。

此外,在 ComboBoxTextField 上使用 setOnAction 或使用 setOnKeyPressed 都无法实现所需的行为。

下面是一个SSCCE来演示:

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);
    }
}

作为了解事件如何工作的一般方法,您始终可以使用 Event.ANY 添加事件过滤器并查看会发生什么,例如。 g.:

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

事件被触发,如控制台中所示。所以你需要的是像这样为关键代码添加一个过滤器:

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

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

});

关于您的问题,您可以查看 ComboBoxListViewSkin,您可以在其中看到事件已被消耗。

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();
    } 
    ...
}

简而言之:使用 EventFilter 而不是 EventHandler。

您可以在 Handling JavaFX Events 文档中阅读更多相关信息。