【问题标题】:JavaFX Display Enum with String field in Combobox as String (in TableView)JavaFX 在组合框中将字符串字段显示为字符串(在 TableView 中)
【发布时间】:2018-03-27 20:50:14
【问题描述】:

我的目标是在 tableView 中显示 Class 实例的每个字段。该类有一个枚举类型的字段,其中有一个字符串类型的字段。 枚举应作为字符串字段名称显示在 ComboBox 中。 当然它也必须是可编辑的。

现在什么不起作用: 枚举类的 String 字段只有在 ComboBox 被点击时才会显示,否则为枚举常量的名称。此外,如果选择了组合框中的另一个枚举,则无法将其提交以进行编辑。单击返回不会取消选择组合框,也不会调用 commitEdit 方法。如果选择了其他列进行编辑,则尝试的编辑将被取消。

我付出了一些努力来解决这个问题,所以我想也许有人可以在这里帮助我。 由于最初的任务是关于企业软件中更大的类,我将它抽象出来问这个问题。

我知道我可以制作包含 String 类型枚举的列,并使其与 MyEnum.values() 和 MyEnum.valueOf() 一起使用,但由于原始类太大而性能不佳,因此无法投入生产.

这里以我的代码为例,如果您不理解问题,只需尝试使用组合框一次,您就会看到。

TableView 类型的类:

public class MyClass {

private MyEnum myEnum;

private String string;

public MyClass(MyEnum myEnum, String string) {
    this.myEnum = myEnum;
    this.string = string;
}

public MyEnum getMyEnum() {
    return myEnum;
}

public void setMyEnum(MyEnum myEnum) {
    this.myEnum = myEnum;
}

public String getString() {
    return string;
}

}

它是枚举字段:

public enum MyEnum {

EnumOne("First Enum"),
EnumTwo("Second Enum");

private String name;

public String getName() {
    return name;
}

private MyEnum(String name) {
    this.name = name;
}

}

外汇应用:

public class NewFXMain extends Application {

@Override
public void start(Stage primaryStage) {
    ObservableList<MyClass> items = FXCollections.observableArrayList();
    items.add(new MyClass(MyEnum.EnumOne, "String"));
    TableView<MyClass> table = new TableView(items);
    table.setEditable(true);
    TableColumn<MyClass, MyEnum> myEnumColumn = new TableColumn();
    TableColumn<MyClass, String> stringColumn = new TableColumn();

    stringColumn.setCellFactory(TextFieldTableCell.forTableColumn());
    stringColumn.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getString()));



    myEnumColumn.setCellFactory((param) -> new MyEnumComboBoxCell());
    myEnumColumn.setCellValueFactory(data -> new ReadOnlyObjectWrapper(data.getValue().getMyEnum()));
    myEnumColumn.setOnEditCommit(
            event -> {
                event.getRowValue().setMyEnum(event.getNewValue());
                System.out.println(event.getRowValue().getMyEnum());

            });

    table.getColumns().addAll(myEnumColumn, stringColumn);

    StackPane root = new StackPane();
    root.getChildren().add(table);
    Scene scene = new Scene(root, 300, 250);
    primaryStage.setScene(scene);
    primaryStage.show();
}

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    launch(args);
}

}

class MyEnumComboBoxCell extends ComboBoxTableCell<MyClass, MyEnum> {

private ComboBox<MyEnum> box;

public MyEnumComboBoxCell() {
    box = new ComboBox<>(FXCollections.observableArrayList(MyEnum.values()));
    box.setCellFactory(new Callback<ListView<MyEnum>, ListCell<MyEnum>>() {
        @Override
        public ListCell<MyEnum> call(ListView<MyEnum> param) {
            return new ListCell<MyEnum>() {
                @Override
                protected void updateItem(MyEnum item, boolean empty) {
                    super.updateItem(item, empty);
                    if ( item != null ) setText(item.getName());
                }

            };
        }
    });
}

@Override
public void startEdit() {
    super.startEdit();
    setGraphic(box);
}

@Override
public void commitEdit(MyEnum newValue) {
    super.commitEdit(newValue);
    if ( newValue != null ) {
        setText(newValue.getName());
        getTableView().getSelectionModel().getSelectedItem().setMyEnum(newValue);
        box.setValue(newValue);
    }
}

@Override
public void updateItem(MyEnum item, boolean empty) {
    super.updateItem(item, empty);
    if ( empty ) {
        setGraphic(null);
    } else {
        setGraphic(null);
        setText(item.getName());
    }
}

}

【问题讨论】:

    标签: java javafx enums combobox tableview


    【解决方案1】:

    不要在updateItem 中设置名称,而是使用StringConverter 之类的:

    public class MyEnumConverter extends StringConverter<MyEnum>{
    
        @Override public String toString(MyEnum enumConstant) {
            return enumConstant.getName();
        }
    
        @Override public MyEnum fromString(String string) {
            return MyEnum.valueOf(string);
        }
    }
    

    然后在单元格的构造函数中:

    this.setConverter(new MyEnumConverter());
    

    编辑:你可能不是@Override 的所有ComboBoxTableCell 的方法,因为它们都按你想要的方式工作。另一方面,您不应为表格单元格指定自己的 ComboBox,因为它有一个。您只需添加一个StringConverter 并设置项目。

    你可以这样使用:

    myEnumColumn.setCellFactory((param) -> new ComboBoxTableCell<>(new StringConverter<MyEnum>() {
                @Override public String toString(MyEnum object) {
                    return object.getName();
                }
    
                @Override public MyEnum fromString(String string) {
                    return MyEnum.valueOf(string);
                }
            }, MyEnum.values()));
    

    如果您愿意,可以像我之前提到的那样为 StringConverter 创建一个单独的类,然后就简单了:

    myEnumColumn.setCellFactory(factory -> new ComboBoxTableCell<>(new MyEnumConverter(), MyEnum.values()));
    

    你也可以去掉myEnumColumn.setOnEditCommit

    【讨论】:

    • 我尝试实施您的解决方案,但它仍然无法正常工作,尽管有点不同。您是否真的重写了我的示例并且它确实有效?我以前自己试过,所以我想可能不会?
    • 我已经编辑了答案,因为我在您的代码中发现了另一个问题。]
    【解决方案2】:

    非常感谢!实际上我已经花了一天的时间,部分和另一个人在一起,所以这真的很感激! :)

    但是: 我必须实现 setOnEditCommit 否则支持 tableColumn 的 myEnum 字段不会改变!有了这个一切正常。没有,只会改变显示的内容。

        myEnumColumn.setOnEditCommit(
                event ->
        {
            event.getRowValue().setMyEnum(event.getNewValue());
    
        });
    

    【讨论】:

    • 是的,您可以使用此解决方案来设置支持模型的值,但是通过创建一个包含一行信息的模型类,有一种非常优雅的方法可以做到这一点,然后一切都会发生而没有任何人工干预。
    猜你喜欢
    • 2016-03-30
    • 1970-01-01
    • 2015-08-03
    • 2012-03-11
    • 1970-01-01
    • 2012-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多