Combobox 在底层数据被修改时触发动作事件

Combobox fires action event when underlying data is modified

我一直在为这个问题困惑一段时间,只是想看看其他人之前是否 运行 遇到过这个问题,或者我是否做错了什么。

给定一个 javafx 实现,其中我们使用一个组合框,其项目是从 ObservableArrayList 中设置的,可以更新、修改、替换等,以及一个带有动作侦听器的组合框,只要它被触发就注销.

package sample;

import java.util.Arrays;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;

public class Main extends Application {

    ObservableList<String> theList = FXCollections.observableArrayList();

    @Override
    public void start(Stage primaryStage) throws Exception{
        primaryStage.setTitle("Sample");
        FlowPane root = new FlowPane(Orientation.VERTICAL);
        root.setVgap(20);

        List<String> initialColors = Arrays.asList("red", "green", "blue", "black");
        theList.addAll(initialColors);

        ComboBox<String> theComboBox = new ComboBox<>();
        theComboBox.setItems(theList);
        theComboBox.setOnAction( event -> {
            System.out.println(String.format("theComboBox action listener triggered, current value is %s", theComboBox.getValue()));
        });
        
        Button bttn1 = new Button("Press me");
        bttn1.setOnAction(event -> {
            List<String> someColors = Arrays.asList("red", "orange", "mauve", "pink", "blue", "salmon", "chiffon");
            System.out.println("About to issue setAll against observable list");
            theList.setAll(someColors);
        });

        root.getChildren().add(theComboBox);
        root.getChildren().add(bttn1);

        primaryStage.setScene(new Scene(root, 100, 150));
        primaryStage.show();

        System.out.println("Setting initial selection to \"blue\"");
        theComboBox.setValue("blue");

    }


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

我认为只有在用户通过直接操作更改组合框时才应触发操作事件,但我看到在修改可观察列表时会触发事件。

我们使用的是 javafx 版本 11.0.2

我应该将此记录为 Gluon 的错误吗?

编辑:更新示例

在此示例中,您可以看到只要通过 setAll 修改基础数据,就会触发操作事件。如果操作事件有某种方式来区分它是来自直接用户交互还是来自对基础数据的编程更改,那就没问题了。

其他奇怪的行为,如果您 select “黑色”然后点击“按下我”按钮,则不会触发动作事件,然后组合框将 select 粉红色,因为它在列表中的相同位置 - 但随后 select 再次变为红色甚至粉红色,您将分别得到 null、red、null 和 null、pink、null。

即使 selection 不再存在,我希望组合框保留其值,而且我也不希望在修改可观察列表时触发这些事件 - 如果您 needed/wanted 要在修改可观察列表时监听事件,您可以直接将监听器附加到它。

总结一下,查看问题的评论以了解更多详细信息。

我们认为这是 javafx 11.0.2 中的错误 - 我已经通过 openjdk jira 提交了错误报告。

目前的解决方法是设置一个标志布尔变量,并且仅在它为真时在侦听器中执行操作。

像添加一样简单的东西:

private boolean actionEventsOn = true;
theComboBox.setOnAction( event -> {
    if(actionEventsOn){
        System.out.println(String.format("theComboBox action listener triggered, current value is %s", theComboBox.getValue()));
    }
});
bttn1.setOnAction(event -> {
    List<String> someColors = Arrays.asList("red", "orange", "mauve", "pink", "blue", "salmon", "chiffon");
    System.out.println("About to issue setAll against observable list");
    actionEventsOn = false;
    theList.setAll(someColors);
    actionEventsOn = true;
});

这应该可以防止不必要地触发动作事件。