【问题标题】:JavaFX: How can you get setCellValueFactory to ignore empty items in an ObservableArray?JavaFX:如何让 setCellValueFactory 忽略 ObservableArray 中的空项?
【发布时间】:2020-05-14 16:24:03
【问题描述】:

我是java新手,不完全了解Javafx的结构,所以我在这里迷路了。

这是我正在学习的课程的库存管理应用程序。

我有两个继承自抽象类的类,以及一个包含两个子类实例的 ObservableList。现在,当我尝试使用 cellvaluefactory 在 TableView 中同时显示这两个类时,由于缺少其中一个或另一个属性,我会收到错误消息。该程序可以编译,但警告是由于其各自实例中缺少的任何字段中的字段“缺失”。 (PartOutsourced 缺少“machineId”字段,PartInhouse 缺少“companyName”字段。

UI picture

我知道必须有某种方法让 cellValueFactory 忽略空值或用空字符串填充它们,但我不知道如何,而且谷歌一直是死路一条。

这是两个子类:

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

【问题讨论】:

  • 为了使继承起作用,所有重要的方法都应该在抽象类中。这样,各个子类就可以根据您的需要返回适当的值。

标签: java javafx observablelist


【解决方案1】:

使用您自己的 Callback 实现(例如,使用 lambda)而不是 PropertyValueFactory(无论如何,这通常是推荐的;PropertyValueFactory 实际上只是在引入 lambda 表达式之前编写为占位符,因为实现了 @带有内部类的 987654324@ 非常冗长)。然后,如果对象是正确的类型,则可以返回所需的属性(例如包装值的 IntegerProperty),如果不是,则返回包装 null 的属性(例如 ObjectProperty&lt;Number&gt;)。

由于您的machineIdNumber,您应该使用

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 属性:

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 的知识),但这让它发挥了作用。
猜你喜欢
  • 2021-12-31
  • 2011-02-05
  • 2017-04-03
  • 2014-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-12
  • 1970-01-01
相关资源
最近更新 更多