Search code examples
javajavafxjavafx-8

JavaFx: ComboBox dynamic text change


I am trying to update the text in a combobox when an element is changed without reinitializing the items or the item.

Is there a way to bind the item's text to the displayed text? Even if I use a Property it seems the StringConverter ignores it, which is understandable, but I am wondering if there is a way to do a binding without reinitializing the item. Here is the reinitialization solion: JavaFx: ComboBox editor's text , which i want to avoid.

Here is a simple code which you can verify:

public class MainStageController implements Initializable {

    @FXML
    private ComboBox<Hero> comboBox;
    @FXML
    private Button lvlUp;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        comboBox.setConverter(new StringConverter<Hero>() {
            @Override
            public String toString(Hero hero) {
                return hero.getName() + " - Level: " +  hero.getLevel();
            }

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

        lvlUp.setOnAction(event -> {
            Hero value = comboBox.getValue();
            value.levelProperty().setValue(value.getLevel() + 1);
        });

        Hero weakHero = new Hero("Ted", 1);
        Hero averageHero = new Hero("Zed", 10);
        Hero strongHero = new Hero("Med", 25);



        lvlUp.disableProperty().bind(comboBox.valueProperty().isNull());
        comboBox.setItems(FXCollections.observableArrayList(weakHero, averageHero, strongHero));
    }

    private static class Hero {

        private String name;
        private IntegerProperty level;

        public Hero(String name, Integer level) {
            this.name = name;
            this.level = new SimpleIntegerProperty(level);
        }

        private String getName() {
            return name;
        }

        private int getLevel() {
            return level.get();
        }

        public IntegerProperty levelProperty() {
            return level;
        }
    }
}

What I want: When I press Level up, update the text both in the displayed text and in the dropdown.

enter image description here enter image description here

Is that possible?


Solution

  • I explained how to use an Extractor. Using a StringConverter, no listeners ....I am using JavaFX 8...

     public class UpdateableComboBox extends Application {
    
        @Override
        public void start(Stage primaryStage) throws Exception {
            ObservableList<Hero> heros 
            = FXCollections.observableArrayList((Hero param) -> new Observable[] { param.nameProperty(), param.levelProperty() });
            heros.add(new Hero("Ted", 1));
            heros.add(new Hero("Zed", 10));
            heros.add(new Hero("Med", 25));
    
            ComboBox<Hero> comboBox = new ComboBox<>();
            comboBox.setPrefWidth(350);
            comboBox.setItems(heros);
            Button button = new Button("Level Up");
            button.setOnAction(e -> {
                 Hero value = comboBox.getValue();
                 value.levelProperty().setValue(value.getLevel() + 1);
            });
    
            comboBox.setConverter(new StringConverter<Hero>() {
                @Override
                public String toString(Hero hero) {
                    return hero.getName() + " - Level: " +  hero.getLevel();
                }
    
                @Override
                public Hero fromString(String string) {
                    return null;
                }
            });
    
            HBox hbox = new HBox(comboBox, button);
            Scene scene = new Scene(hbox, 500, 100);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
    
        }
    
        private  class Hero {
            private StringProperty name = new SimpleStringProperty();
            private IntegerProperty level = new SimpleIntegerProperty();
            Hero(String name, int level){
                this.name.set(name);
                this.level.set(level);
            }
            public final StringProperty nameProperty() {
                return this.name;
            }
    
            public final String getName() {
                return this.nameProperty().get();
            }
    
            public final void setName(final String name) {
                this.nameProperty().set(name);
            }
    
            public final IntegerProperty levelProperty() {
                return this.level;
            }
    
            public final int getLevel() {
                return this.levelProperty().get();
            }
    
            public final void setLevel(final int level) {
                this.levelProperty().set(level);
            }
    
        }
    
    }