【问题标题】:Accessing nested properties in JavaFx TableView / TableColumn访问 JavaFx TableView / TableColumn 中的嵌套属性
【发布时间】:2019-12-21 08:48:30
【问题描述】:

我有一个 TableView,并按如下方式访问列表对象的属性。这工作得很好。

    <TableColumn fx:id="dateColumn" editable="false" prefWidth="135.0" text="Date">
        <cellValueFactory>
            <PropertyValueFactory property="date" />
        </cellValueFactory>
    </TableColumn>

但是,我想访问对象的嵌套属性,例如:

        <TableColumn prefWidth="100.0" text="Course">
            <cellValueFactory>
                <PropertyValueFactory property="house.bathroom"/>
            </cellValueFactory>
        </TableColumn>

我的列表对象有一个getHouse(),而House 有一个getBathroom()。不幸的是,这不起作用。我尝试了几种拼写变体,但都没有成功。

【问题讨论】:

  • 找到了我的意思:有一个look at ReactFx,它曾经支持(现在还支持?)路径绑定

标签: java javafx properties tablecolumn


【解决方案1】:

我不相信您可以通过 FXML 做到这一点(尽管我可能是错的)。

假设您使用正确的 JavaFX 属性,您只需在控制器中设置自己的 CellValueFactory,如下所示:

bathroomColumn.setCellValueFactory(tf -> tf.getValue().getHouse().bathroomProperty());

由于不清楚您想在浴室栏中显示什么,这将返回 BathroomProperty

但是,如果您想返回Bathroom 对象 的属性,您也只需调用getBathroom().yourProperty()

bathroomColumn.setCellValueFactory(tf -> tf.getValue().getHouse().getBathroom().myStringProperty());

也许一个例子可能有助于展示这个概念:

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TableViewValues extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        // Simple Interface
        VBox root = new VBox(10);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(10));

        // Simple TableView
        TableView<Person> personTableView = new TableView<>();
        TableColumn<Person, String> colName = new TableColumn<>("Name");
        TableColumn<Person, String> colCar = new TableColumn<>("Car");

        // Setup the CellValueFactories
        colName.setCellValueFactory(tf -> tf.getValue().nameProperty());
        colCar.setCellValueFactory(tf -> tf.getValue().getCar().modelProperty());

        personTableView.getColumns().addAll(colName, colCar);

        root.getChildren().add(personTableView);

        // Sample Data
        personTableView.getItems().addAll(
                new Person("Jack", new Car("Accord")),
                new Person("John", new Car("Mustang")),
                new Person("Sally", new Car("Yugo"))
        );

        // Show the stage
        primaryStage.setScene(new Scene(root));
        primaryStage.setTitle("Sample");
        primaryStage.show();
    }
}

class Person {

    private final StringProperty name = new SimpleStringProperty();
    private final ObjectProperty<Car> car = new SimpleObjectProperty<>();

    public Person(String name, Car car) {
        this.name.set(name);
        this.car.set(car);
    }

    public String getName() {
        return name.get();
    }

    public void setName(String name) {
        this.name.set(name);
    }

    public StringProperty nameProperty() {
        return name;
    }

    public Car getCar() {
        return car.get();
    }

    public void setCar(Car car) {
        this.car.set(car);
    }

    public ObjectProperty<Car> carProperty() {
        return car;
    }
}

class Car {
    private final StringProperty model = new SimpleStringProperty();

    public Car(String model) {
        this.model.set(model);
    }

    public String getModel() {
        return model.get();
    }

    public void setModel(String model) {
        this.model.set(model);
    }

    public StringProperty modelProperty() {
        return model;
    }
}

结果:


如果您使用的是纯 Java bean,则过程类似。但是,您无需在数据模型类中将 CellValueProperty 设置为 Property,而是创建一个新的 StringProperty 内联并将您需要的 bean 值传递给它。

因此,在上面的 Car 示例中,您应该这样做:

colName.setCellValueFactory(tf -> new SimpleStringProperty(tf.getValue().getName()));
colCar.setCellValueFactory(tf -> new SimpleStringProperty(tf.getValue().getCar().getModel()));

旁注:您在上面看到的tf 只是我用来引用Java 中的CellDataFeatures 对象的一个​​变量,我们可以使用它来获取对该行数据模型的引用对象(使用getValue() 方法)。或许cdf 会是更好的选择,但习惯很难改掉。

【讨论】:

  • 谢谢。我必须检查nul吗? .例如,浴室可能为空,因此显然从浴室访问属性是行不通的。另外,我这里使用的是 pojos,而不是使用 StringProperty 等的类。
  • @StealthRabbi - 我更新了我的答案以包含使用标准 POJO bean 实现此功能的方法。
  • 注意:当您将汽车设置在人身上时,模型的单元格值不会自动更新!
  • @kleopatra 指出的潜在问题应该可以通过Bindings.select 解决(尽管我相信这会使内联编辑稍微复杂一些)。第三方库可能会提供select 的类型安全版本。
  • @StealthRabbi 您可能想通过minimal reproducible example 提出一个新问题来演示该问题。但是,我会说: (1) 绑定使用弱侦听器,因此当被绑定的Property 持有对目标ObservableValue 的强引用时,反之则不然; (2) Disposer 类使用 PhantomReferences 和 ReferenceQueue,这意味着如果它“认为”实例不可访问,那是因为它们是——毕竟,该功能是由垃圾收集器驱动的。
猜你喜欢
  • 2012-08-21
  • 1970-01-01
  • 2020-10-20
  • 2020-05-07
  • 1970-01-01
  • 2018-10-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多