JavaFX:如何让 setCellValueFactory 忽略 ObservableArray 中的空项?
JavaFX: How can you get setCellValueFactory to ignore empty items in an ObservableArray?
我是java的新手,对Javafx的结构还不是很了解,所以在这里杂草丛生。
这是我正在学习的课程的库存管理应用程序。
我有两个继承自抽象 class 的 classes 和一个包含 child classes 实例的 ObservableList。现在,当我尝试在带有 cellvaluefactory 的 TableView 中同时显示两个 class 时,由于其中一个或另一个缺少属性,我会收到错误消息。该程序编译但警告是由于字段 "missing" 来自其各自实例中缺少的字段。 (PartOutsource 缺少 "machineId" 字段,PartInhouse 缺少 "companyName" 字段。
UI picture
我知道一定有某种方法可以让 cellValueFactory 忽略空值或用空字符串填充它们,但我不知道如何,google 一直是死胡同。
这是两个 child classes:
public class PartOutsourced extends Part {
private String companyName;
public PartOutsourced(String name, int stock, double price, int min, int max, String companyName) {
super(name, stock, price, min, max);
this.companyName = companyName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
}
public class PartInHouse extends Part {
private int machineId;
public PartInHouse(String name, int stock, double price, int min, int max, int machineId) {
super(name, stock, price, min, max);
this.machineId = machineId;
}
public int getMachineId() {
return machineId;
}
public void setMachineId(int machineId) {
this.machineId = machineId;
}
}
这里是 cellValueFactory 代码:
col_id.setCellValueFactory(new PropertyValueFactory<Part, String>("id"));
col_name.setCellValueFactory(new PropertyValueFactory<Part, String>("name"));
col_stock.setCellValueFactory(new PropertyValueFactory<Part, String>("stock"));
col_price.setCellValueFactory(new PropertyValueFactory<Part, String>("price"));
col_min.setCellValueFactory(new PropertyValueFactory<Part, String>("min"));
col_max.setCellValueFactory(new PropertyValueFactory<Part, String>("max"));
col_machine_id.setCellValueFactory(new PropertyValueFactory<Part, String>("machineId"));
col_company.setCellValueFactory(new PropertyValueFactory<Part, String>("companyName"));
一点堆栈跟踪:
May 14, 2020 12:14:06 PM javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'machineId' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory@5f88bef3 with provided class type: class inventory.datamodel.PartOutsourced
java.lang.IllegalStateException: Cannot read from unreadable property machineId
使用您自己的 Callback
实现(例如使用 lambda)而不是 PropertyValueFactory
(无论如何通常推荐这样做;PropertyValueFactory
实际上只是作为 lambda 之前的占位符编写的引入了表达式,因为使用内部 class 实现 Callback
非常冗长)。然后你可以 return 你需要的 属性 (例如 IntegerProperty
包装值)如果对象是正确的类型,或者 属性 包装 null (例如 ObjectProperty<Number>
) 如果没有。
因为你的 machineId
是 Number
,你应该使用
private TableColumn<Part, Number> col_machine_id ; // note: please use proper Java naming conventions
然后你可以做
col_machine_id.setCellValueFactory(cellData -> {
Part part = cellData.getValue() ;
if (part instanceof PartInHouse) {
return new SimpleIntegerProperty(((PartInHouse)part).getMachineId());
}
return new SimpleObjectProperty<>(null);
});
请注意,还建议在您的模型中使用 JavaFX 属性 class:
public class PartInHouse extends Part {
private final IntegerProperty machineId = new SimpleIntegerProperty();
public PartInHouse(String name, int stock, double price, int min, int max, int machineId) {
super(name, stock, price, min, max);
setMachineId(machineId);
}
public IntegerProperty machineIdProperty() {
return machineId ;
}
public final int getMachineId() {
return machineIdProperty().get();
}
public final void setMachineId(int machineId) {
machineIdProperty().set(machineId);
}
}
在这种情况下,您可以使用以下单元格值工厂:
col_machine_id.setCellValueFactory(cellData -> {
Part part = cellData.getValue() ;
if (part instanceof PartInHouse) {
return ((PartInHouse)part).machineIdProperty();
}
return new SimpleObjectProperty<>(null);
});
这是一个完整的 运行 示例:
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class InheritanceTableModelTest extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
TableView<Part> table = new TableView<>();
for (int i = 1 ; i <= 20 ; i++) {
table.getItems().add(new PartInHouse("Part "+(2*i), i));
table.getItems().add(new PartOutsourced("Part "+(2*i+1), "Company "+i));
}
TableColumn<Part, String> nameCol = new TableColumn<>("Part");
TableColumn<Part, Number> machineIdCol = new TableColumn<>("Machine ID");
TableColumn<Part, String> companyCol = new TableColumn<>("Company");
nameCol.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
machineIdCol.setCellValueFactory(cellData -> {
Part part = cellData.getValue();
if (part instanceof PartInHouse) {
return ((PartInHouse)part).machineIdProperty();
}
return new SimpleObjectProperty<>(null);
});
companyCol.setCellValueFactory(cellData -> {
Part part = cellData.getValue();
if (part instanceof PartOutsourced) {
return ((PartOutsourced)part).companyNameProperty();
}
return new SimpleObjectProperty<>(null);
});
table.getColumns().add(nameCol);
table.getColumns().add(machineIdCol);
table.getColumns().add(companyCol);
Scene scene = new Scene(new BorderPane(table));
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Part {
private final StringProperty name = new SimpleStringProperty();
public Part(String name) {
setName(name);
}
public StringProperty nameProperty() {
return name;
}
public final String getName() {
return nameProperty().get();
}
public final void setName(String name) {
nameProperty().set(name);
}
}
public static class PartInHouse extends Part {
private final IntegerProperty machineId = new SimpleIntegerProperty() ;
public PartInHouse(String name, int machineId) {
super(name);
setMachineId(machineId);
}
public IntegerProperty machineIdProperty() {
return machineId ;
}
public int getMachineId() {
return machineIdProperty().get();
}
public void setMachineId(int machineId) {
machineIdProperty().set(machineId);
}
}
public static class PartOutsourced extends Part {
private final StringProperty companyName = new SimpleStringProperty();
public PartOutsourced(String name, String companyName) {
super(name);
setCompanyName(companyName);
}
public StringProperty companyNameProperty() {
return companyName ;
}
public String getCompanyName() {
return companyNameProperty().get();
}
public void setCompanyName(String companyName) {
companyNameProperty().set(companyName);
}
}
public static void main(String[] args) {
Application.launch(args);
}
}
我是java的新手,对Javafx的结构还不是很了解,所以在这里杂草丛生。
这是我正在学习的课程的库存管理应用程序。
我有两个继承自抽象 class 的 classes 和一个包含 child classes 实例的 ObservableList。现在,当我尝试在带有 cellvaluefactory 的 TableView 中同时显示两个 class 时,由于其中一个或另一个缺少属性,我会收到错误消息。该程序编译但警告是由于字段 "missing" 来自其各自实例中缺少的字段。 (PartOutsource 缺少 "machineId" 字段,PartInhouse 缺少 "companyName" 字段。
UI picture
我知道一定有某种方法可以让 cellValueFactory 忽略空值或用空字符串填充它们,但我不知道如何,google 一直是死胡同。
这是两个 child classes:
public class PartOutsourced extends Part {
private String companyName;
public PartOutsourced(String name, int stock, double price, int min, int max, String companyName) {
super(name, stock, price, min, max);
this.companyName = companyName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
}
public class PartInHouse extends Part {
private int machineId;
public PartInHouse(String name, int stock, double price, int min, int max, int machineId) {
super(name, stock, price, min, max);
this.machineId = machineId;
}
public int getMachineId() {
return machineId;
}
public void setMachineId(int machineId) {
this.machineId = machineId;
}
}
这里是 cellValueFactory 代码:
col_id.setCellValueFactory(new PropertyValueFactory<Part, String>("id"));
col_name.setCellValueFactory(new PropertyValueFactory<Part, String>("name"));
col_stock.setCellValueFactory(new PropertyValueFactory<Part, String>("stock"));
col_price.setCellValueFactory(new PropertyValueFactory<Part, String>("price"));
col_min.setCellValueFactory(new PropertyValueFactory<Part, String>("min"));
col_max.setCellValueFactory(new PropertyValueFactory<Part, String>("max"));
col_machine_id.setCellValueFactory(new PropertyValueFactory<Part, String>("machineId"));
col_company.setCellValueFactory(new PropertyValueFactory<Part, String>("companyName"));
一点堆栈跟踪:
May 14, 2020 12:14:06 PM javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'machineId' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory@5f88bef3 with provided class type: class inventory.datamodel.PartOutsourced
java.lang.IllegalStateException: Cannot read from unreadable property machineId
使用您自己的 Callback
实现(例如使用 lambda)而不是 PropertyValueFactory
(无论如何通常推荐这样做;PropertyValueFactory
实际上只是作为 lambda 之前的占位符编写的引入了表达式,因为使用内部 class 实现 Callback
非常冗长)。然后你可以 return 你需要的 属性 (例如 IntegerProperty
包装值)如果对象是正确的类型,或者 属性 包装 null (例如 ObjectProperty<Number>
) 如果没有。
因为你的 machineId
是 Number
,你应该使用
private TableColumn<Part, Number> col_machine_id ; // note: please use proper Java naming conventions
然后你可以做
col_machine_id.setCellValueFactory(cellData -> {
Part part = cellData.getValue() ;
if (part instanceof PartInHouse) {
return new SimpleIntegerProperty(((PartInHouse)part).getMachineId());
}
return new SimpleObjectProperty<>(null);
});
请注意,还建议在您的模型中使用 JavaFX 属性 class:
public class PartInHouse extends Part {
private final IntegerProperty machineId = new SimpleIntegerProperty();
public PartInHouse(String name, int stock, double price, int min, int max, int machineId) {
super(name, stock, price, min, max);
setMachineId(machineId);
}
public IntegerProperty machineIdProperty() {
return machineId ;
}
public final int getMachineId() {
return machineIdProperty().get();
}
public final void setMachineId(int machineId) {
machineIdProperty().set(machineId);
}
}
在这种情况下,您可以使用以下单元格值工厂:
col_machine_id.setCellValueFactory(cellData -> {
Part part = cellData.getValue() ;
if (part instanceof PartInHouse) {
return ((PartInHouse)part).machineIdProperty();
}
return new SimpleObjectProperty<>(null);
});
这是一个完整的 运行 示例:
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class InheritanceTableModelTest extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
TableView<Part> table = new TableView<>();
for (int i = 1 ; i <= 20 ; i++) {
table.getItems().add(new PartInHouse("Part "+(2*i), i));
table.getItems().add(new PartOutsourced("Part "+(2*i+1), "Company "+i));
}
TableColumn<Part, String> nameCol = new TableColumn<>("Part");
TableColumn<Part, Number> machineIdCol = new TableColumn<>("Machine ID");
TableColumn<Part, String> companyCol = new TableColumn<>("Company");
nameCol.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
machineIdCol.setCellValueFactory(cellData -> {
Part part = cellData.getValue();
if (part instanceof PartInHouse) {
return ((PartInHouse)part).machineIdProperty();
}
return new SimpleObjectProperty<>(null);
});
companyCol.setCellValueFactory(cellData -> {
Part part = cellData.getValue();
if (part instanceof PartOutsourced) {
return ((PartOutsourced)part).companyNameProperty();
}
return new SimpleObjectProperty<>(null);
});
table.getColumns().add(nameCol);
table.getColumns().add(machineIdCol);
table.getColumns().add(companyCol);
Scene scene = new Scene(new BorderPane(table));
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Part {
private final StringProperty name = new SimpleStringProperty();
public Part(String name) {
setName(name);
}
public StringProperty nameProperty() {
return name;
}
public final String getName() {
return nameProperty().get();
}
public final void setName(String name) {
nameProperty().set(name);
}
}
public static class PartInHouse extends Part {
private final IntegerProperty machineId = new SimpleIntegerProperty() ;
public PartInHouse(String name, int machineId) {
super(name);
setMachineId(machineId);
}
public IntegerProperty machineIdProperty() {
return machineId ;
}
public int getMachineId() {
return machineIdProperty().get();
}
public void setMachineId(int machineId) {
machineIdProperty().set(machineId);
}
}
public static class PartOutsourced extends Part {
private final StringProperty companyName = new SimpleStringProperty();
public PartOutsourced(String name, String companyName) {
super(name);
setCompanyName(companyName);
}
public StringProperty companyNameProperty() {
return companyName ;
}
public String getCompanyName() {
return companyNameProperty().get();
}
public void setCompanyName(String companyName) {
companyNameProperty().set(companyName);
}
}
public static void main(String[] args) {
Application.launch(args);
}
}