JavaFX Combobox 显示元素的属性

sym*_*yri 1 java combobox javafx

我目前正在使用 Java 和 JavaFX 开发一款游戏。我正在使用 JavaFX ComboBox。

下面的例子应该可以解释我的问题。

假设我有一个“动物”类,其属性为“名称”、“年龄”和“颜色”。

第一个文件:

public class Animal {
    private String name;
    private int age;
    private String color;

    public Animal(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我想为我创建的每只动物创建一个组合框。

第二个文件:

ComboBox<Animal> comboBoxAnimal = new ComboBox();
ObservableList<Animal> comboBoxItems = FXCollections.observableArrayList();

Animal dog = new Animal("Liam", 2, "Brown");
Animal cat = new Animal("Emily", 5, "Gray");
Animal bird = new Animal("Kian", 3, "Green");

comboBoxItems.addAll(dog, cat, bird);

comboBoxAnimal.setItems(comboBoxItems);
Run Code Online (Sandbox Code Playgroud)

目前我只得到“Animal@xxxxxxxx”,这是可以理解的,因为我有一个动物组合框,但只想显示名称(字符串)。

只是简单地创建一个ComboBox<String>并不能解决问题,因为我需要一个Combobox<Animal>.

我怎样才能得到一个Combobox<Animal>但是因为元素只显示每个动物的名字?

感谢您的反馈意见 :)

jew*_*sea 8

两种选择:

  1. 使用细胞工厂。
  2. 使用字符串转换器。

本答案中使用的单元工厂和字符串转换器示例产生相同的输出:

截屏

细胞工厂实施

使用细胞工厂,就像这个答案一样:

链接的答案适用于 ListView,但 ComboBox 类似,TableView 或其他依赖单元工厂进行显示的虚拟化控件也是如此。

要为组合框下拉列表和按钮配置单元格,请调用setCellFactorysetButtonCell

这是最灵活的解决方案,并且允许进行超出文本字符串范围的自定义。可以创建图形节点来完全自定义每个组合框单元的视觉表示。

示例代码

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.stage.Stage;

public class AnimalComboApp extends Application {

    public record Animal(String name, int age, String color) {}

    public static class AnimalCell extends ListCell<Animal> {
        @Override
        public void updateItem(Animal animal, boolean empty) {
            super.updateItem(animal, empty);

            if (animal == null || empty) {
                setText(null);
            } else {
                setText(animal.name());
            }
        }
    }

    @Override
    public void start(Stage stage) throws Exception {
        ComboBox<Animal> comboBox = new ComboBox<>();
        comboBox.getItems().setAll(
                new Animal("Liam", 2, "Brown"),
                new Animal("Emily", 5, "Gray"),
                new Animal("Kian", 3, "Green")
        );

        comboBox.setCellFactory(listView -> new AnimalCell());
        comboBox.setButtonCell(new AnimalCell());
        comboBox.getSelectionModel().select(0);

        stage.setScene(new Scene(comboBox));
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Run Code Online (Sandbox Code Playgroud)

字符串转换器实现

单元工厂定义的替代方法是为 ComboBox 提供 StringConverter 它可以在字符串和对象之间进行转换。

需要StringConverterfromStringtoString实现,但fromString实现可以返回null,除非您还希望用户能够执行文本编辑来编辑组合框值。

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;

public class AnimalComboApp extends Application {

    public record Animal(String name, int age, String color) {}

    @Override
    public void start(Stage stage) throws Exception {
        ComboBox<Animal> comboBox = new ComboBox<>();
        comboBox.getItems().setAll(
                new Animal("Liam", 2, "Brown"),
                new Animal("Emily", 5, "Gray"),
                new Animal("Kian", 3, "Green")
        );

        comboBox.setConverter(new StringConverter<>() {
            @Override
            public String toString(Animal animal) {
                return animal.name();
            }

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

        comboBox.getSelectionModel().select(0);

        Scene scene = new Scene(comboBox);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Run Code Online (Sandbox Code Playgroud)

不使用的选项

toString() 实现

不要覆盖toString()以自定义单元格,这是一种反模式。

用于toString()其他目的,例如列出和调试 Animal 类的所有元素,而是使用适当的方法(例如单元工厂或字符串转换器)来自定义Animal.

将节点放置在组合框列表中

您可能还想尝试将节点直接放入 ComboBox 列表中(例如,在每个 Label 中创建带有对象名称的 Label,然后创建一个ComboBox<Label>)。

不要这样做,正如ComboBox API 文档部分所建议的:“关于将节点插入 ComboBox 项目列表的警告”,它会在您的应用程序中产生错误。