JAVAFX 8 ComboBox and ObservableList

Andrea picture Andrea · Mar 2, 2016 · Viewed 7.5k times · Source

I need a combobox populated through observablelist which contains specific data retrieved from DB. This is my source.

Model

public ObservableList<Bank> listBank = FXCollections.observableArrayList();

public static class Bank {
            private final StringProperty id;
            private final StringProperty name;

            private Bank(
                    String id, 
                    String name
            ) {
            this.id = new SimpleStringProperty(id);
            this.name = new SimpleStringProperty(name);        
            }

            public StringProperty idProperty() { return id; }
            public StringProperty nameProperty() { return name; }        
        }

View

@FXML
private ComboBox comboBank<Bank>;

public final void getBankDataFields() {
        comboBank.setItems(model.listBank); 
    }

comboBank.setButtonCell(new ListCell<Bank>() {
                @Override
                protected void updateItem(Bank t, boolean bln) {
                    super.updateItem(t, bln);
                    if (t != null) {
                        setText(t.nameProperty().getValue().toUpperCase());
                    } else {
                        setText(null);
                    }
                }
            });

comboBank.setCellFactory(new Callback<ListView<Bank>, ListCell<Bank>>() {
                @Override 
                public ListCell<Bank> call(ListView<Bank> p) {
                    return new ListCell<Bank>() { 
                        @Override
                        protected void updateItem(Bank t, boolean bln) {
                            super.updateItem(t, bln);
                            if(t != null){
                                setText(t.nomeProperty().getValue().toUpperCase());
                            } else {
                                setText(null);
                            }    

                        }                       
                    };
                }
            });

comboBank.valueProperty().addListener((ObservableValue<? extends Bank> observable, Bank oldValue, Bank newValue) -> {
                setIdBank(newValue.idProperty().getValue());
            });

ComboBox is populated with NAME field and listener is used to get relative ID and pass it to a query for storing data on DB.

Ok, everything seems to work but i have two questions:

  1. When user need to modify this record, i need to get the ID from DB and select the relative NAME in ComboBox. How can i do that?

    comboBank.setValue(????);

  2. Is there a better way to achieve this goal? An ObservableMap may substitute the ObservableList?

Thanks in advance.

Answer

ItachiUchiha picture ItachiUchiha · Mar 2, 2016

There is an easier way to what you are trying to achieve. You should use a StringConverter on the ComboBox to display the names for the Bank instances.

comboBox.setConverter(new StringConverter<Bank>() {

    @Override
    public String toString(Bank object) {
       return object.nameProperty().get();
    }

    @Override
    public Bank fromString(String string) {
       // Somehow pass id and return bank instance
       // If not important, just return null
       return null;
    }
});

To get selected value i.e. instance of the selected bank, just use :

comboBox.getValue();

MCVE

import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.util.StringConverter;

import java.util.stream.Collectors;

public class Main extends Application {

    @Override
    public void start(Stage stage) {

        ComboBox<Bank> comboBox = new ComboBox<>();
        ObservableList<Bank> items = FXCollections.observableArrayList(
                new Bank("1", "A"), new Bank("2", "B"),
                new Bank("3", "C"), new Bank("4", "D"));
        comboBox.setItems(items);
        StringConverter<Bank> converter = new StringConverter<Bank>() {
            @Override
            public String toString(Bank bank) {
                return bank.nameProperty().get();
            }

            @Override
            public Bank fromString(String id) {
                return items.stream()
                        .filter(item -> item.idProperty().get().equals(id))
                        .collect(Collectors.toList()).get(0);
            }
        };
        comboBox.setConverter(converter);
        // Print the name of the Bank that is selected
        comboBox.getSelectionModel().selectedItemProperty().addListener((o, ol, nw) -> {
            System.out.println(comboBox.getValue().nameProperty().get());
        });
        // Wait for 3 seconds and select the item with id = 2
        PauseTransition pauseTransition = new PauseTransition(Duration.seconds(3));
        pauseTransition.setOnFinished(event -> comboBox.getSelectionModel().select(converter.fromString("2")));
        pauseTransition.play();
        VBox root = new VBox(comboBox);
        root.setAlignment(Pos.CENTER);
        Scene scene = new Scene(root, 200, 200);
        stage.setScene(scene);
        stage.show();
    }
}