从组合框删除项目时发生JavaFX不必要的更改事件

时间:2019-03-07 16:42:08

标签: javafx

我有一个JavaFX ComboBox,我需要从中删除一个项目,但是一旦删除了一个项目,它将触发3-4个不需要的更改事件。有人可以帮助我避免那些不需要的事件吗?

我的代码是这样的:

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.ComboBox;

public class ComboboxTest
{
private Boolean comboBoxRemovingMode = false;

public ComboBox<String> createCombo()
{

    final ComboBox<String> myComboBox = new ComboBox<>();
    myComboBox.getItems().addAll("prompt_txt", "A", "B", "C");
    myComboBox.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
        @Override
        public void changed(final ObservableValue<? extends Number> ov, final Number oldvalue, final Number newvalue)
        {

            if (comboBoxRemovingMode) {
                return;
            }
            if ((newvalue == null) || (newvalue.intValue() < 0) || (myComboBox.getItems().get(newvalue.intValue()).equalsIgnoreCase("prompt_txt"))) {
                return;
            }

            synchronized (comboBoxRemovingMode) {
                comboBoxRemovingMode = myComboBox.getItems().remove("prompt_txt");
                // .... some actions
                myComboBox.getSelectionModel().select(newvalue.intValue() - 1);
                comboBoxRemovingMode = false;

            }
        }

    });

    return myComboBox;
}

public static void main(final String args[])
{
    final ComboboxTest t = new ComboboxTest();
    final ComboBox<String> box = t.createCombo();

    box.getSelectionModel().select(1); // select A

    System.out.println(box.getSelectionModel().getSelectedItem()); // it should be select "A", but it's B
}

}

1 个答案:

答案 0 :(得分:0)

从您的代码看来,您有一个项目充当ComboBox的提示文本。选择新项目后,您要删除提示文本项目,同时保持新选择的项目为 1 。为此,您只需要删除提示文本项即可;无需尝试在选择模型上手动调用select-到目前为止,已经选择了新项。

comboBox.getSelectionModel().selectedIndexProperty((obs, oldVal, newVal) -> {
    int oldIndex = oldVal.intValue();
    var items = comboBox.getItems();
    if (oldIndex >= 0 && oldIndex < items.size() && items.get(oldIndex).equalsIgnoreCase("prompt_txt")) {
        items.remove(oldIndex);
    }
});

这里我使用旧索引,假设您将"prompt_txt"项作为最初选择的项。

由于删除"prompt_txt"项目将更改所有其余项目的索引,因此该代码仍将导致两次更改。没关系。侦听器不会对任何后续通知执行任何操作,并且新选择的项目保持不变。但是,由于侦听器的唯一工作似乎是删除"prompt_txt",因此在第一个通知之后删除侦听器可能是明智的。一种方法如下:

comboBox.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<>() {

    @Override
    public void changed(ObservableValue<? extends Number> obs, Number oldVal, Number newVal) {
        int oldIndex = oldVal.intValue();
        var items = comboBox.getItems();
        if (oldIndex >= 0 && oldIndex < items.size() && items.get(oldIndex).equalsIgnoreCase("prompt_txt")) {
            obs.removeListener(this); // Needed anonymous class to reference "this"
            items.remove(oldIndex);
        }
    }

});

在这种情况下,由于我在调用remove(oldIndex)之前删除了监听器,所以监听器仅被通知一次。

但是

所有这些,不需要添加特殊项目来表示提示文本。 ComboBoxBase继承的ComboBox类具有promptText属性。这是文档:

  

要显示的ComboBox提示文本,如果没有显示提示文本,则为null。并非在所有情况下都显示提示文本,而是取决于ComboBoxBase的子类来阐明何时显示提示文本。例如,在大多数情况下,当组合框不可编辑时,提示文本将永远不会显示(即,提示文本仅在通过文本输入允许用户输入时显示)。

一些快速测试显示ComboBox即使没有editable也会显示提示文本(只要未选择任何项目)。


1。您在// some actions...remove("prompt_text")之间有select(newvalue.intValue() - 1。这些动作可能完全使我的答案无效。