2016-08-12 67 views
1

我处于以下情况。我从模型类Foo有数据填充一个TableViewJavaFX - TableView - 该字段的字段和字段的更改

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

只需使用JavaFX的API,你可以做

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

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

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


对于一个更强大和更少的传统风格的实现,你可以用托马斯Mikula的ReactFX library,2.0或更高版本,其中包括像这样绑定的支持。使用该库你会做

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

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

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"));