JavaFX将组合框中具有字符串字段的枚举显示为字符串(在TableView中)



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

现在什么不起作用:只有在单击ComboBox时才会显示enum类的String字段,否则它是枚举常量的名称。此外,如果选择了组合框中的另一个枚举,则无法对其进行编辑。单击return不会取消选择组合框,也不会调用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());
}
}
}

不要在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的方法,因为所有方法都可以按照您的意愿工作。另一方面,您不应该为表单元格指定自己的组合框,因为它有一个。您只需要添加一个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

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

但是:我必须实现setOnEditCommit,否则支持tableColumn的myEnum字段不会更改!有了这个,一切都会运转起来。否则,只会更改显示的内容。

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

最新更新