我有一个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
}
}
答案 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
。这些动作可能完全使我的答案无效。