JavaFX TableView嵌套属性绑定

时间:2016-10-26 09:13:34

标签: javafx binding properties nested tableview

我有一个包含复杂数据类型列表的对象列表,我需要将这些属性绑定到我的TableView。 我的实体看起来像这样:

public class Customer
{
   StringProperty property1;
   StringProperty property2;
   ....
   List<Contract> contracts;
}


public class Contract
{
    StringProperty property1;
    StringProperty property2;
    ....
}

我的observableArrayList包含一个Customer列表,其中包含一个Contract列表。 获取客户属性很简单:

sampleColumn1.setCellValueFactory(celldata -> celldata.getValue().sampleProperty1());
sampleColumn2.setCellValueFactory(celldata -> celldata.getValue().sampleProperty2());
...

但我无法获得合同清单的属性。 目前我执行以下解决方法:

PropertyValueFactory<Customer, List<Contract>> contractFactory = new PropertyValueFactory<>("contracts");
contractIdColumn.setCellValueFactory(contractFactory);
contractIdColumn.setCellFactory(celldata -> new TableCell<Customer>, List<Contract>>(){
@Override
public void updateItem(List<Contract> contracts, boolean empty){
    super.updateItem(contracts, empty);
    if(empty)
    setText("");            
    else
    setText(contracts.stream().map(Contract::getContractId)
   .collect(Collectors.joining("\n")));
}
});

但是这段代码很脏,有人知道用cellValueFactory和lambda表达式做这个的方法吗? 有什么建议吗?

2 个答案:

答案 0 :(得分:0)

单元格值工厂只是Callback获取CellDataFeatures并返回适当的可观察值,因此您应该可以执行以下操作:

contractIdColumn.setCellValueFactory(cellDataFeatures -> new SimpleStringProperty(cellDataFeatures.getValue().contracts.stream()
    .map(Contract::getContractId)
    .collect(Collectors.joining("\n"))));  

请注意,如果您使用ObservableList而不是列表,则可以使用Bindings.createStringBinding,以便在列表更新但Customer元素不会更改时更新值。

答案 1 :(得分:0)

我不认为你的代码太糟糕了。这里重要的是将单元格中显示的数据(由cellValueFactory提供)与数据的呈现方式(由cellFactory提供)分开,你有那。数据显然是合同清单,所以你当然想要

TableColumn<Customer, List<Contract>> contractIdColumn ;

并且您需要将单元格值设为ObservableValue<List<Contract>>,您可以按照以下方式执行此操作:

contractIdColumn.setCellValueFactory(new PropertyValueFactory<>("contracts"));

或者,以类型安全的方式,

contractIdColumn.setCellValueFactory(cellData -> 
    new SimpleObjectProperty<>(cellData.getValue().getContracts()));

然后,您当前的单元工厂将以文本形式显示合同列表,每个合同ID都在新行上。你可以很容易地修改单元工厂(不改变单元值工厂)来使用,例如ListView<Contract>

contractIdColumn.setCellFactory(celldata -> new TableCell<Customer>, List<Contract>>(){

    private final ListView<Contract> listView = new ListView<>();

    @Override
    public void updateItem(List<Contract> contracts, boolean empty){
        super.updateItem(contracts, empty);
        if(empty)
            setGraphic(null);            
        else {
            listView.getItems().setAll(contracts);
            setGraphic(listView);
        }
    }

});

(只是一个粗略的例子;您可能需要设置单元格样式以正确匹配列表视图,并假设Contract具有适当的toString();您可能需要设置单元格工厂ListView也是,等等。)