I'm trying to create a dropdown that will display a user's first name, last name and userId in javafx

55 views Asked by At

I'm creating a javafx/fxml app. I have a dropdown that displays first name, last name and and ID. I want the dropdown to have the headers for each column and also display the data in that appropriate column. How would I go about creating this dropdown?

I have tried created a list view within the combo box and that didn't work properly. I have also tried to use the tableview and that I cannot also get to work appropriately.

1

There are 1 answers

2
Sai Dandem On BEST ANSWER

You can set a cell factory to the ComboBox that creates the cells in the way you are looking for. However it will be tricky to implement the headers and scroll only the value cells.

To keep the things simple, I would rather go with a custom implementation that looks like a drop-down but built with some different nodes.

The general idea is:

  • Create a button to display the value.
  • When you click the button, you show a TableView in a Popup that is placed at the bottom of the button.
  • When a row is clicked the value/text in the button is updated and the popup is closed.

Please check the below demo. If this doesn't suite your needs, then I think you need to go with the cell factory implementation.

enter image description here

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Bounds;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;

public class DropDownWithTableDemo extends Application {
    String defaultVal = "Select...";

    ObjectProperty<TableObj> valueObj = new SimpleObjectProperty<>();

    @Override
    public void start(Stage primaryStage) throws Exception {
        TableView<TableObj> tableView = buildTable(valueObj);
        Popup popup = new Popup();
        popup.getContent().add(tableView);
        popup.setAutoHide(true);

        Label valueLabel = new Label(defaultVal);
        valueLabel.setMaxWidth(Double.POSITIVE_INFINITY);
        HBox.setHgrow(valueLabel, Priority.ALWAYS);

        StackPane arrow = new StackPane();
        arrow.setStyle("-fx-background-color:#444444;-fx-shape:\"M 0 0 h 7 l -3.5 4 z\";-fx-padding: 4px;");
        arrow.setMaxSize(8, 8);

        HBox pane = new HBox(10, valueLabel, arrow);
        pane.setAlignment(Pos.CENTER_LEFT);
        pane.setMaxWidth(Double.POSITIVE_INFINITY);

        Button dropDownBtn = new Button();
        dropDownBtn.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        dropDownBtn.setPrefWidth(150);
        dropDownBtn.setGraphic(pane);
        dropDownBtn.setOnMouseClicked(e -> {
            if (!popup.isShowing()) {
                Bounds bounds = dropDownBtn.localToScreen(dropDownBtn.getLayoutBounds());
                popup.show(dropDownBtn, bounds.getMinX(), bounds.getMaxY());
            }
        });

        valueObj.addListener((obs, old, val) -> {
            if (val != null) {
                valueLabel.setText(val.firstName.getValue());
            } else {
                valueLabel.setText(defaultVal);
            }
            popup.hide();
        });

        Scene scene = new Scene(new StackPane(dropDownBtn), 400, 200);
        primaryStage.setTitle("TableView DropDown");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private TableView<TableObj> buildTable(ObjectProperty<TableObj> valueObj) {
        TableView<TableObj> tableView = new TableView<>();
        TableColumn<TableObj, String> idCol = new TableColumn<>("ID");
        TableColumn<TableObj, String> fnCol = new TableColumn<>("First Name");
        TableColumn<TableObj, String> lnCol = new TableColumn<>("Last Name");

        idCol.setCellValueFactory(p -> p.getValue().id);
        fnCol.setCellValueFactory(p -> p.getValue().firstName);
        lnCol.setCellValueFactory(p -> p.getValue().lastName);

        ObservableList<TableObj> items = FXCollections.observableArrayList();
        for (int x = 1; x < 50; x++) {
            items.add(new TableObj("" + x, "First " + x, "Last " + x));
        }

        tableView.getColumns().addAll(idCol, fnCol, lnCol);
        tableView.setItems(items);
        tableView.setRowFactory(param -> new TableRow<>() {
            {
                setOnMouseClicked(e -> {
                    if (getItem() != null) {
                        valueObj.set(getItem());
                    }
                });
            }
        });
        return tableView;
    }

    class TableObj {
        private StringProperty id;
        private StringProperty firstName;
        private StringProperty lastName;

        public TableObj(String test1, String test2, String test3) {
            this.id = new SimpleStringProperty(test1);
            this.firstName = new SimpleStringProperty(test2);
            this.lastName = new SimpleStringProperty(test3);
        }
    }
}