如何在JavaFX中创建多列组合框?

Was*_*han 2 user-interface combobox javafx

我正在尝试创建一个ComboBox在其下拉菜单中显示多个列的。

这是显示我希望它的外观的屏幕截图:

多列组合框

有什么建议么?

我脑海中唯一的解决方案是通过扩展ComboBox和自定义多列容器来创建自定义容器。

但是JavaFX甚至提供给我创建自定义UI容器的选项吗?

如何创建自定义UI容器以及如何在FXML中使用它?

Zep*_*hyr 5

您无需扩展ComboBox即可创建类似的布局。相反,您只需要提供自己的实现即可CellFactory

通过创建自定义CellFactory,您可以ComboBox通过提供自己Listcell的商品(在下拉菜单中实际上可以选择的商品)来控制商品的显示方式。

我敢肯定有很多方法可以完成此操作,但是对于本示例,我将使用a GridPane作为我的的根布局ListCell

下面的完整示例也包含注释:

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        // Simple Interface
        VBox root = new VBox(10);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(10));

        // List of sample Persons
        ObservableList<Person> persons = FXCollections.observableArrayList();
        persons.addAll(
                new Person("Maria Anders", "Sales Representative", "Zurich"),
                new Person("Ana Trujillo", "Owner", "Sydney"),
                new Person("Thomas Hardy", "Order Administrator", "Dallas")
        );

        // Create a simple ComboBox of Persons
        ComboBox<Person> cboPersons = new ComboBox<>();
        cboPersons.setItems(persons);

        // We need a StringConverter in order to ensure the selected item is displayed properly
        // For this sample, we only want the Person's name to be displayed
        cboPersons.setConverter(new StringConverter<Person>() {
            @Override
            public String toString(Person person) {
                return person.getName();
            }

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

        // Provide our own CellFactory to control how items are displayed
        cboPersons.setCellFactory(cell -> new ListCell<Person>() {

            // Create our layout here to be reused for each ListCell
            GridPane gridPane = new GridPane();
            Label lblName = new Label();
            Label lblTitle = new Label();
            Label lblLocation = new Label();

            // Static block to configure our layout
            {
                // Ensure all our column widths are constant
                gridPane.getColumnConstraints().addAll(
                        new ColumnConstraints(100, 100, 100),
                        new ColumnConstraints(100, 100, 100),
                        new ColumnConstraints(100, 100, 100)
                );

                gridPane.add(lblName, 0, 1);
                gridPane.add(lblTitle, 1, 1);
                gridPane.add(lblLocation, 2, 1);

            }

            // We override the updateItem() method in order to provide our own layout for this Cell's graphicProperty
            @Override
            protected void updateItem(Person person, boolean empty) {
                super.updateItem(person, empty);

                if (!empty && person != null) {

                    // Update our Labels
                    lblName.setText(person.getName());
                    lblTitle.setText(person.getTitle());
                    lblLocation.setText(person.getLocation());

                    // Set this ListCell's graphicProperty to display our GridPane
                    setGraphic(gridPane);
                } else {
                    // Nothing to display here
                    setGraphic(null);
                }
            }
        });

        // Add the ComboBox to the scene
        root.getChildren().addAll(
                new Label("Select Person:"),
                cboPersons
        );

        // Show the stage
        primaryStage.setScene(new Scene(root));
        primaryStage.setTitle("Sample");
        primaryStage.show();
    }
}

// Simple Person class to represent our...Persons
class Person {

    private final StringProperty name = new SimpleStringProperty();
    private final StringProperty title = new SimpleStringProperty();
    private final StringProperty location = new SimpleStringProperty();

    Person(String name, String title, String location) {
        this.name.set(name);
        this.title.set(title);
        this.location.set(location);
    }

    public String getName() {
        return name.get();
    }

    public void setName(String name) {
        this.name.set(name);
    }

    public StringProperty nameProperty() {
        return name;
    }

    public String getTitle() {
        return title.get();
    }

    public void setTitle(String title) {
        this.title.set(title);
    }

    public StringProperty titleProperty() {
        return title;
    }

    public String getLocation() {
        return location.get();
    }

    public void setLocation(String location) {
        this.location.set(location);
    }

    public StringProperty locationProperty() {
        return location;
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

屏幕截图