Display Combobox values from numbers

2019-01-29 11:30发布

问题:

I have a int value which I want to use for configuration. It can have 2 values - 0 for active and 1 for Blocked. I want to display this into friendly combo box:

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class MainApp extends Application
{
    @Override
    public void start(Stage stage) throws Exception
    {
        int state = 0;

        ObservableList<String> options = FXCollections.observableArrayList(
            "Active",
            "Blocked"
        );
        ComboBox comboBox = new ComboBox(options);
        BorderPane bp = new BorderPane(comboBox);
        bp.setPrefSize(800, 800);
        Scene scene = new Scene(bp);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args)
    {
        launch(args);
    }
}

It's not clear for me how I have to implement this into JavaFX Combobox. When I have 0 I want to display this as Active and when I have 1 I want to display Blocked and also when I change the ComboBox value to update also int state value.

回答1:

There are different ways to solve this problem. I have listed three of the solutions below. You can use any one of the below solutions which you feel is apt for your scenario.

Using a custom class

Create a custom class KeyValuePair, for storing the string and its corresponding value. Exposed the getters for the required fields.

Later, I have used the setCellFactory() of the comboxbox to show the required data. Use StringConverter to show the key in place of the object.

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;

public class Main extends Application {

    @Override
    public void start(Stage stage) throws Exception
    {
        KeyValuePair keyValuePair1 = new KeyValuePair("Active", 0);
        KeyValuePair keyValuePair2 = new KeyValuePair("Blocked", 1);


        ObservableList<KeyValuePair> options = FXCollections.observableArrayList();
        options.addAll(keyValuePair1, keyValuePair2);

        ComboBox<KeyValuePair> comboBox = new ComboBox<>(options);

        // show the correct text
        comboBox.setCellFactory((ListView<KeyValuePair> param) -> {
            final ListCell<KeyValuePair> cell = new ListCell<KeyValuePair>(){

                @Override
                protected void updateItem(KeyValuePair t, boolean bln) {
                    super.updateItem(t, bln);

                    if(t != null){
                        setText(String.valueOf(t.getKey()));
                    }else{
                        setText(null);
                    }
                }

            };
            return cell;
        });


        comboBox.setConverter(new StringConverter<KeyValuePair>() {
            @Override
            public String toString(KeyValuePair object) {
                return object.getKey();
            }

            @Override
            public KeyValuePair fromString(String string) {
                return null; // No conversion fromString needed.
            }
        });


        // print the value
        comboBox.valueProperty().addListener((ov, oldVal, newVal) -> {
            System.out.println(newVal.getKey() + " - " + newVal.getValue());
        });

        BorderPane bp = new BorderPane(comboBox);
        bp.setPrefSize(800, 800);
        Scene scene = new Scene(bp);
            stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    class KeyValuePair {
        private final String key;
        private final int value;

        public KeyValuePair(String key, int value) {
            this.key = key;
            this.value = value;
        }

        public String getKey() {
            return key;
        }

        public int getValue() {
            return value;
        }
    }
}

Without using an extra class

As suggested by @kleopatra, you can even do this without using an extra class.

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;

public class Main extends Application {

    @Override
    public void start(Stage stage) throws Exception {

        ObservableList<Integer> options = FXCollections.observableArrayList();
        options.addAll(1, 0);

        ComboBox<Integer> comboBox = new ComboBox<>(options);

        // show the correct text
        comboBox.setCellFactory((ListView<Integer> param) -> {
            final ListCell<Integer> cell = new ListCell<Integer>(){

                @Override
                protected void updateItem(Integer t, boolean bln) {
                    super.updateItem(t, bln);

                    if(t != null){
                        setText(t == 1 ? "Active" : "Blocked");
                    }else{
                        setText(null);
                    }
                }

            };
            return cell;
        });


        comboBox.setConverter(new StringConverter<Integer>() {
              @Override
              public String toString(Integer object) {
                  return object == 1 ? "Active" : "Blocked";
              }

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

        // print the value
        comboBox.valueProperty().addListener((ov, oldVal, newVal) -> {
            System.out.println("Changed from " + oldVal + " to " + newVal);
        });

        BorderPane bp = new BorderPane(comboBox);
        bp.setPrefSize(800, 800);
        Scene scene = new Scene(bp);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Using Bindings

You can also use Bindings if you don't want to take the pain of creating a new class and you will always have two elements i.e. Active and Blocked.

Just bind the valueProperty() of your combobox to the state, which is supposed to store the value i.e. 0 or 1.

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        IntegerProperty state = new SimpleIntegerProperty();
        ObservableList options = FXCollections.observableArrayList("Active", "Blocked");

        ComboBox<String> comboBox = new ComboBox<>(options);
        state.bind(Bindings.when(comboBox.valueProperty().isEqualTo("Active")).then(0).otherwise(1));

        BorderPane bp = new BorderPane(comboBox);
        bp.setPrefSize(800, 800);
        Scene scene = new Scene(bp);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}


回答2:

Here is another solution:

declare state as BooleanProperty:

   private BooleanProperty state = new SimpleBooleanProperty(false);

bind state property to the valueProperty of comboBox:

 comboBox.valueProperty().bind(new When(state).then("Active").otherwise("Blocked"));

complete example:

public class ComboboxTest extends Application {

    private BooleanProperty state = new SimpleBooleanProperty(false);
    private Button button;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {

        ObservableList<String> options = FXCollections.observableArrayList(
                "Active",
                "Blocked"
        );
        ComboBox comboBox = new ComboBox(options);
        button = new Button("false");
        button.setOnAction(e -> setSate());
        button.textProperty().bind(state.asString());
        BorderPane bp = new BorderPane(comboBox);
        StackPane stackpane = new StackPane(button);
        stackpane.setAlignment(Pos.CENTER);
        bp.setTop(stackpane);
        bp.setPrefSize(800, 800);
        Scene scene = new Scene(bp);
        stage.setScene(scene);
        stage.show();
        comboBox.valueProperty().bind(new When(state).then("Active").otherwise("Blocked"));
    }

    public void setSate() {
        if (state.get()) {
            state.set(false);

        } else {
            state.set(true);
        }
    }

}