Reputation: 2604
I have a comboBox cb
and an ObservableList<StringProperty> data
I have bound the cb
's Items
to data
as follows:
Bindings.bindContent(cb.getItems(), data);
Suppose data
has the following items: str1, str2, str3, str4
When I change data
, the combobox gets the new list without any problem.
But if str3
is selected in cb
and I change the value of str3
to NewStr3
in data, that change is not getting displayed in cb. And sometimes the list displayed is also wrong (it shows str3 instead of NewStr3) eventhough underlying data it refers is correct.
How can I force combobox to display new values when the underlying model is changed?
Upvotes: 1
Views: 698
Reputation: 51524
Oops ... mis-read the comboBox for a choiceBox - while the basics of this answer apply to both combo- and choiceBox, I don't have a custom ComboBoxX - yet :-)
Basically, it's the responsibility of the SelectionModel to update itself on changes to the items. The intended behaviour implemented in core is to completely clear the selection - that is, null the selectedItem and set selectedIndex to -1 - if the old item was the selectedItem and is replaced or removed. The typical solution for custom behaviour is to implement a custom selection model and set it:
/**
* A SelectionModel that updates the selectedItem if it is contained in
* the data list and was replaced/updated.
*
* @author Jeanette Winzenburg, Berlin
*/
public static class MySelectionModel<T> extends ChoiceBoxSelectionModel<T> {
public MySelectionModel(ChoiceBoxX<T> cb) {
super(cb);
}
@Override
protected void itemsChanged(Change<? extends T> c) {
// selection is in list
if (getSelectedIndex() != -1) {
while (c.next()) {
if (c.wasReplaced() || c.wasUpdated()) {
if (getSelectedIndex() >= c.getFrom()
&& getSelectedIndex() < c.getTo()) {
setSelectedItem(getModelItem(getSelectedIndex()));
return;
}
}
}
}
// super expects a clean change
c.reset();
super.itemsChanged(c);
}
}
// usage
myChoiceBox.setSelectionModel(new MySelectionModel(myChoiceBox));
Unfortunately, core choiceBox doesn't play by the rule - it severely interferes with model's responsibilities (probably because the model implementation doesn't stand up to its duties) which requires a complete re-write of the whole collaborator-stack (choiceBox, -skin, copied -behaviour) such as ChoiceBoxX - which I did just to learn a bit, try remove some of its smells and fix some bugs.
Upvotes: -1
Reputation: 209225
The selected item in a combo box is not required to be an element of the combo box's items list. (For example, in an editable combo box, you can type in an item which is not in the list.) If you think about your example from this perspective, it's no surprise that it behaves as you describe.
If you want to force the selected value to be an element of the underlying list when that list may change, you need to define how the selected item should change if the list changes in a way in which it no longer contains the selected item (it is not obvious how you will do this, and probably depends on your application logic). Once you know what you want to do, you can implement it with a ListChangeListener
:
cb.getItems().addListener((ListChangeListener.Change change) -> {
String newSelectedItem = ... ; // figure item that should be selected instead
cb.setValue(newSelectedItem);
});
The simplest implementation would be just cb.setValue(null);
, which would mean no item was selected if the list changed so that it no longer contained the currently selected item.
Upvotes: 2