Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX 2.0 Choice Box Issue. How to update a choiceBox, which represents a list of objects, when an object is updated?

I have a choiceBox which represents a list objects. When the name representing one of those objects is changed by another bit of code the name in the drop down list for the choice box does not change. For example if I have a choice box which is made up of list Test objects. The Code for Test is shown below:

class Test {
    String name;

    public Test(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return name; 
    }
} 

Then have a choice Box as follows:

ChoiceBox<Test> chi = new ChoiceBox<>();
ObservableList<Test> items = FXCollections.observableArrayList();
chi.setItems(items);
items.addAll(new Test("ITEM1"),new Test("ITEM2"),new Test("ITEM3"));

The ChoiceBox will show the list ITEM1, ITEM2 and ITEM3

If I then change the name of one of the items via the following code:

items.get(1).setName("CHANGED");

The ChoiceBox will still show the list ITEM1, ITEM2 and ITEM3. How can I make it so the choiceBox will update and show the list ITEM1, CHANGED and ITEM3?

like image 366
Steven Avatar asked Feb 18 '14 12:02

Steven


2 Answers

Just for completeness - in fx2 you are probably stuck with the replace approach as outlined in the other answer. Since fx8, there's a mechanism to tell the list to listen to changes of its contained items (precondition being, of course, that your item has properties and notifies listeners on change):

/** changed item to 
 *  - use property and notify on change
 *  - not override toString (for visuals, use converter instead)
 */ 
class Test {
    StringProperty name;

    public Test(String name) {
        setName(name);
    }

    public StringProperty nameProperty() {
         if (name == null) name = new SimpleStringProperty(this, "name");
         return name;
    }
    public void setName(String name) {
        nameProperty().set(name);
    }

    public String getName() {
        return nameProperty().get();
    }

} 

// use in collection with extractor
ObservableList<Test> items = FXCollections.observableList(
    e -> new Observable[] {e.nameProperty()} );
items.addAll(...);
choiceBox = new ChoiceBox<>(items);
// tell the choice how to represent the item
StringConverter<Test> converter = new StringConverter<Test>() {

    @Override
    public String toString(Test album) {
        return album != null ? album.getName() : null;
    }

    @Override
    public Test fromString(String string) {
        return null;
    }

};
choiceBox.setConverter(converter);
like image 165
kleopatra Avatar answered Oct 02 '22 15:10

kleopatra


I had the same issue in JavaFX 8 (with ComboBox too). I was able to get the same functionality by removing the item then adding a new one at the same location.

Example:

This gets selected item, creates a new item, then calls the replace method:

Channel selected = channelChoiceBox.getSelectionModel().getSelectedItem();
Channel newChan = new Channel("Example", "Channel");
replaceChannel(newChan, selected);

This replaces the selected channel with the new one, effectively editing it:

private void replaceChannel(Channel newChan, Channel oldChan) {
    int i = channelChoiceBox.getItems().indexOf(oldChan);
    channelChoiceBox.getItems().remove(oldChan);
    channelChoiceBox.getItems().add(i, newChan);
    channelChoiceBox.setValue(newChan);
}

It's not ideal, but does the job.

Disclaimer: I'm new to Java and programming in general.

like image 44
Huon Imberger Avatar answered Oct 02 '22 14:10

Huon Imberger