如何在 parent class 属性 传递到 JavaFX 中的 PropertyValueFactory 时填充 TableView 数据?

How to populate TableView data when parent class property is passed into PropertyValueFactory in JavaFX?

我试图将 TableColumn 添加到我的 TableView 时出现错误,因为我的 PropertyValueFactory 无法读取其中的 属性。这是因为我传递给它的 属性 来自 parent class。无论如何,PropertyValueFactory 是否因为 super 功能而通过 child class 接受 parent class 数据?代码贴在下面。我查看了其他 SO 帖子,但它们没有说明当您使用继承 class 属性.

时该怎么做

Parent Class

public abstract class User {
    private String username;
    private String password;
    
    public User(String username, String password){
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    
}

Child Class

public class Customer extends User {
    private int points;
    
    public Customer(String username, String password, int points){
        super(username,password);
        this.points = points;
    }

    public int getPoints() {
        return points;
    }

    public void setPoints(int points) {
        this.points = points;
    }
}

表格列代码

TableColumn<Customer,String> customerUsernameCol = new TableColumn<>("Customer Username");
customerUsernameCol.setMinWidth(100);
customerUsernameCol.setCellValueFactory(new PropertyValueFactory<>("username")); //Does not work as intended

TableColumn<Customer,String> customerPasswordCol = new TableColumn<>("Customer Password");
customerPasswordCol.setMinWidth(100);
customerPasswordCol.setCellValueFactory(new PropertyValueFactory<>("password")); //Does not work as intended

TableColumn<Customer,Integer> customerPointsCol = new TableColumn<>("Customer Points");
customerUsernameCol.setMinWidth(100);
customerUsernameCol.setCellValueFactory(new PropertyValueFactory<>("points"));

不要使用 PropertyValueFactory. Define your own CellValueFactory. You just need to implement the appropriate Callback
(代码后的注释。)

import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;

public class TblVwTst extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Customer customer1 = new Customer("George", "Best", 8);
        TableView<Customer> tblVw = new TableView<>();
        ObservableList<Customer> items = tblVw.getItems();
        items.add(customer1);
        TableColumn<Customer, String> usernameColumn = new TableColumn<>("User");
        Callback<TableColumn.CellDataFeatures<Customer, String>, ObservableValue<String>> usernameColumnCellValue;
        usernameColumnCellValue = cellDataFeatures -> {
            Customer customer = cellDataFeatures.getValue();
            String username = customer.getUsername();
            ObservableValue<String> usernameObservableValue = new SimpleStringProperty(username);
            return usernameObservableValue;
        };
        usernameColumn.setCellValueFactory(usernameColumnCellValue);
        TableColumn<Customer, String> passwordColumn = new TableColumn<>("Password");
        Callback<TableColumn.CellDataFeatures<Customer, String>, ObservableValue<String>> passwordColumnCellValue;
        passwordColumnCellValue = cellDataFeatures -> {
            Customer customer = cellDataFeatures.getValue();
            String password = customer.getPassword();
            ObservableValue<String> passwordObservableValue = new SimpleStringProperty(password);
            return passwordObservableValue;
        };
        passwordColumn.setCellValueFactory(passwordColumnCellValue);
        TableColumn<Customer, Number> pointsColumn = new TableColumn<>("Points");
        Callback<TableColumn.CellDataFeatures<Customer, Number>, ObservableValue<Number>> pointsColumnCellValue;
        pointsColumnCellValue = cellDataFeatures -> {
            Customer customer = cellDataFeatures.getValue();
            int points = customer.getPoints();
            ObservableValue<Number> pointsCellValue = new SimpleIntegerProperty(points);
            return pointsCellValue;
        };
        pointsColumn.setCellValueFactory(pointsColumnCellValue);
        ObservableList<TableColumn<Customer, ?>> tblVwColumns = tblVw.getColumns();
        tblVwColumns.add(usernameColumn);
        tblVwColumns.add(passwordColumn);
        tblVwColumns.add(pointsColumn);
        BorderPane root = new BorderPane(tblVw);
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

abstract class User {
    private String username;
    private String password;

    public User(String username, String password){
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

class Customer extends User {
    private int points;

    public Customer(String username, String password, int points){
        super(username,password);
        this.points = points;
    }

    public int getPoints() {
        return points;
    }

    public void setPoints(int points) {
        this.points = points;
    }
}

上面代码中的Callback是由lambda expression since interface Callback contains a single, abstract method named call which takes a single parameter and returns a value. Callback is a generic interface. In the above code, the actual type of the parameter to method call is TableColumn.CellDataFeatures<Customer, String> and the type of the returned value is ObservableValue<String>. The JavaFX infrastructure will call your method and pass it the appropriate argument. You need to extract the relevant value from the supplied method argument and return that value as an ObservableValue. Since the members of your Customer class are not ObservableValues, you need to create one. Hence, in the above code, I return SimpleStringProperty, which is a concrete (i.e. not abstract) class that implements interface ObservableValue, as the cellValueFactory属性实现的usernameColumnpasswordColumn。同样,我 return SimpleIntegerProperty for pointsColumn.

在上面的代码中,我还创建了一个示例 Customer 并将其添加到 TableView

这是我 运行 上述代码时 GUI 的样子。