我遇到以下情况。我有一个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中的更改。
我如何获得"组合"这些解决方案,因此表会监听对象本身及其字段的变化吗?
答案 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
中收到警告。
同样使用此类,您需要使用符合命名约定的属性方法,即在这种情况下方法的名称应为someObjectProperty
和someTextProperty
。这允许您使用类似于PropertyValueFactory
的类:
column.setCellValueFactory(new NestedPropertyValueFactory<>("someObject", "someText"));
或
column.setCellValueFactory(new NestedPropertyValueFactory<>("someObject.someText"));