简体   繁体   English

无论值属性更改如何,都调用ComboBox的enter键/操作事件处理程序

[英]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? 使用可编辑的ComboBox ,有没有办法让ENTER键事件或动作事件处理程序发生,无论Combobox的value属性是否已更改?

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 . 我基本上希望在按下ENTER键的ComboBoxTextField具有相同的行为,就像TextField

What I Have Tried 我曾经尝试过什么

My initial thought was to simply use setOnAction for a ComboBox ; 我最初的想法是简单地使用setOnAction作为ComboBox ; however, according to the documentation for it: 但是,根据它的文件:

The ComboBox action, which is invoked whenever the ComboBox value property is changed. ComboBox操作,每当更改ComboBox值属性时调用。 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. 这可能是由于当用户选择弹出列表或对话框中的项目时,以编程方式更改了value属性,或者,在可编辑的ComboBoxes的情况下,可能是用户提供自己的输入时(通过TextField)或其他一些输入机制。

Thus, by using setOnAction , the event handler only occurs if: 因此,通过使用setOnAction ,事件处理程序仅在以下情况下发生:

  1. The value property is changed via a change in selection from the drop down OR 通过从下拉OR中选择更改来更改value属性
  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). value属性通过用户输入进行更改(即:如果用户未键入任何内容并按ENTER键则不会发生,如果用户在事件处理程序运行一次后没有更改输入并且按Enter键,则不会发生这种情况) 。

Also, neither using setOnAction on the ComboBox 's TextField nor using setOnKeyPressed achieves the desired behaviour. 此外,既没有使用setOnActionComboBoxTextField也不使用setOnKeyPressed实现所期望的行为。

Below is an SSCCE to demonstrate: 以下是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);
    }
}

As a general way of finding out how eventing works, you could always add an eventfilter with Event.ANY and see what happens, eg: 作为了解事件如何工作的一般方法,您总是可以使用Event.ANY添加eventfilter并查看会发生什么,例如:

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. 关于您的问题,您可以查看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();
    } 
    ...
}

So in short: Use an EventFilter instead of an EventHandler. 简而言之:使用EventFilter而不是EventHandler。

You can read more about that in the Handling JavaFX Events documentation. 您可以在处理JavaFX事件文档中阅读更多相关信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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