Peter Penzov
Peter Penzov

Reputation: 1678

Display Label and Progressbar into combo box

I have this code which is used to display text into combo box.

ProgressBar pb1 = new ProgressBar(0.6);
        ProgressIndicator pi1 = new ProgressIndicator(0.6);
        VBox vb1 = new VBox();
        vb1.getChildren().addAll(new Label("Progressbar 1"), pi1);

        ProgressBar pb2 = new ProgressBar(0.6);
        ProgressIndicator pi2 = new ProgressIndicator(0.6);
        VBox vb2 = new VBox();
        vb2.getChildren().addAll(new Label("Progressbar 2"), pi2);

        ProgressBar pb3 = new ProgressBar(0.6);
        ProgressIndicator pi3 = new ProgressIndicator(0.6);
        VBox vb3 = new VBox();
        vb3.getChildren().addAll(new Label("Progressbar 3"), pi3);


        TextChooser textChooser = new TextChooser(
            vb1, vb2, vb3
        );

        textChooser.setStyle("-fx-font: 10px \"Verdana\";");

        VBox layout = new VBox(textChooser);
        layout.setPadding(new Insets(22, 22, 22, 22));



public static class TextChooser extends StackPane {
        private Label label = new Label();
        private ComboBox<String> combo = new ComboBox<>();

        public TextChooser(String... options) {
            StackPane.setAlignment(label, Pos.CENTER_LEFT);
            StackPane.setAlignment(combo, Pos.CENTER_LEFT);

            label.textProperty().bind(
                combo.getSelectionModel().selectedItemProperty()
            );
            label.visibleProperty().bind(
                combo.visibleProperty().not()
            );
            label.setPadding(new Insets(0, 0, 0, 10));

            combo.getItems().setAll(options);
            combo.getSelectionModel().select(0);
            combo.setVisible(false);

            label.setOnMouseEntered(event -> combo.setVisible(true));
            combo.showingProperty().addListener(observable -> {
                if (!combo.isShowing()) {
                    combo.setVisible(false);
                }
            });
            combo.setOnMouseExited(event -> {
                if (!combo.isShowing()) {
                    combo.setVisible(false);
                }
            });

            getChildren().setAll(label, combo);
        }
    }

In my case I cannot insert VBox into the combo box. Any idea how I can fix this?

Upvotes: 1

Views: 391

Answers (1)

Mad Physicist
Mad Physicist

Reputation: 114290

The biggest problem with your code is trying to construct a TextChooser using VBoxes when the formal parameters are Strings. Change your constructor to public TextChooser(VBox... options) and the ComboBox declaration to private ComboBox<VBox> combo = new ComboBox<>();.

Now you will be able to add the items to the combo box, and if it works, you are done. If you experience the issue with adding Nodes to a ComboBox, you may want to add more code. The problem and solution are described in the Javadoc for ComboBox: http://docs.oracle.com/javafx/2/api/javafx/scene/control/ComboBox.html. To get around the fact that the item you select will be removed from the combo box, you need to change this code (taken from the javadoc):

combo.setCellFactory(new Callback<ListView<VBox>, ListCell<VBox>>() {
    @Override public ListCell<VBox> call(ListView<VBox> p) {
        return new ListCell<VBox>() {
            @Override protected void updateItem(VBox item, boolean empty) {
                super.updateItem(item, empty);

                if (item == null || empty) {
                    setGraphic(null);
                } else {
                    setGraphic(item);
                }
            }
        };
    }
});

after the line getItems().setAll(options);.

This is what your full example code would turn into:

    ProgressBar pb1 = new ProgressBar(0.6);
    ProgressIndicator pi1 = new ProgressIndicator(0.6);
    VBox vb1 = new VBox();
    vb1.getChildren().addAll(new Label("Progressbar 1"), pi1);

    ProgressBar pb2 = new ProgressBar(0.6);
    ProgressIndicator pi2 = new ProgressIndicator(0.6);
    VBox vb2 = new VBox();
    vb2.getChildren().addAll(new Label("Progressbar 2"), pi2);

    ProgressBar pb3 = new ProgressBar(0.6);
    ProgressIndicator pi3 = new ProgressIndicator(0.6);
    VBox vb3 = new VBox();
    vb3.getChildren().addAll(new Label("Progressbar 3"), pi3);


    TextChooser textChooser = new TextChooser(
        vb1, vb2, vb3
    );

    textChooser.setStyle("-fx-font: 10px \"Verdana\";");

    VBox layout = new VBox(textChooser);
    layout.setPadding(new Insets(22, 22, 22, 22));



public static class TextChooser extends StackPane {
    private Label label = new Label();
    private ComboBox<VBox> combo = new ComboBox<>();

    public TextChooser(VBox... options) {
        StackPane.setAlignment(label, Pos.CENTER_LEFT);
        StackPane.setAlignment(combo, Pos.CENTER_LEFT);

        label.textProperty().bind(
            combo.getSelectionModel().selectedItemProperty()
        );
        label.visibleProperty().bind(
            combo.visibleProperty().not()
        );
        label.setPadding(new Insets(0, 0, 0, 10));

        combo.getItems().setAll(options);

        // vvvv Begin Optional Part vvvv
        combo.setCellFactory(new Callback<ListView<VBox>, ListCell<VBox>>() {
            @Override public ListCell<VBox> call(ListView<VBox> p) {
                return new ListCell<VBox>() {
                    @Override protected void updateItem(VBox item, boolean empty) {
                        super.updateItem(item, empty);

                        if (item == null || empty) {
                            setGraphic(null);
                        } else {
                            setGraphic(item);
                        }
                    }
                };
            }
        });
        // ^^^^ End Optional Part ^^^^

        combo.getSelectionModel().select(0);
        combo.setVisible(false);

        label.setOnMouseEntered(event -> combo.setVisible(true));
        combo.showingProperty().addListener(observable -> {
            if (!combo.isShowing()) {
                combo.setVisible(false);
            }
        });
        combo.setOnMouseExited(event -> {
            if (!combo.isShowing()) {
                combo.setVisible(false);
            }
        });

        getChildren().setAll(label, combo);
    }
}

Upvotes: 1

Related Questions