JavaFX - TableView - 该字段的字段和字段的更改

时间:2016-08-12 15:33:36

标签: java javafx javafx-8

我遇到以下情况。我有一个TableView填充了模型类Foo中的数据:

public class Foo {
    private StringProperty someText;
    private Bar someObject;

    // getters, setters and properties dropped for clarity
}

此类有一个Bar类型的字段:

public class Bar {
    private StringProperty someText;

    // getters, setters and properties dropped for clarity
}

其中一列必须显示Bar的someText中的文字。所以我将StringProperty绑定到列。

但是当Foo中的整个Bar对象被另一个替换时,表也应该更新。所以我在Foo中创建了一个包含Bar的ObjectProperty,并将该属性绑定到列。当然,现在它不再听取Bar的someText中的更改。

我如何获得"组合"这些解决方案,因此表会监听对象本身及其字段的变化吗?

2 个答案:

答案 0 :(得分:2)

只使用JavaFX API,即可

TableColumn<Foo, String> barColumn = new TableColumn<>("Bar");

barColumn.setCellValueFactory(cellData -> 
    Bindings.selectString(cellData.getValue().barProperty(), "someText"));

出于几个原因,我并不喜欢这部分API。首先,没有编译时检查:您只需将属性的名称作为String提供,因此如果您有输入错误,它只会在运行时显示。其次,如果foo.getBar()返回null(它将在表格单元格中),则会向stderr生成一堆警告。这些只是令人讨厌(它们不会阻止任何运行),并且真的不应该存在,因为这是根据API文档支持的用例。但是,它会起作用。

对于更强大且更少遗留式的实现,您可以使用Tomas Mikula的ReactFX library,版本2.0或更高版本,其中包括对此类绑定的支持。使用该库你会做

barColumns.setCellValueFactory(cellData -> 
    Val.flatMap(cellData.getValue().barProperty(), Bar::someTextProperty));

这有编译时检查和类型检查等,没有虚假警告。

答案 1 :(得分:2)

您可以使用Bindings.select通过多级层次结构选择值。这允许您创建一个cellValueFactory类:

import java.util.Arrays;
import javafx.beans.NamedArg;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TableColumn;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.util.Callback;

public class NestedPropertyValueFactory<S, T> implements Callback<TableColumn.CellDataFeatures<S, T>, ObservableValue<T>> {

    private final String[] steps;
    private final PropertyValueFactory firstStepSelector;

    public NestedPropertyValueFactory(String... properties) {
        firstStepSelector = new PropertyValueFactory<>(properties[0]);
        this.steps = Arrays.copyOfRange(properties, 1, properties.length);
    }

    /**
     * @param property a string containing the names of the properties seperated
     * by '.'. (For easy use from fxml file)
     */
    public NestedPropertyValueFactory(@NamedArg("property") String property) {
        this(property.split("\\."));
    }

    @Override
    public ObservableValue<T> call(TableColumn.CellDataFeatures<S, T> param) {
        // use PropertyValueFactory for first step and Bindings.select for
        // additonal steps.
        return Bindings.select(firstStepSelector.call(param), steps);
    }

}

请注意,如果任何中间步骤产生null,您将在System.err中收到警告。

同样使用此类,您需要使用符合命名约定的属性方法,即在这种情况下方法的名称应为someObjectPropertysomeTextProperty。这允许您使用类似于PropertyValueFactory的类:

column.setCellValueFactory(new NestedPropertyValueFactory<>("someObject", "someText"));

column.setCellValueFactory(new NestedPropertyValueFactory<>("someObject.someText"));