我有一个自定义类BasicDataSet,其中包含一个需要渲染(且可更新)为JavaFX HashMapTableViewBasicDataSet对象表示一行,该列缺少的任何哈希映射值在表中均显示为空字符串。

BasicDataSet包含dataPoints,名称和tagName的哈希映射。将ArrayList<BasicDataSet>传递到方法中后,将提取每个哈希映射对象中的所有键,并筛选出重复项。这些键将成为列标题值,并用于将数据从哈希映射中拉出(在工厂中)。

我的问题是创建一个执行此操作的单元格值工厂。该方法假设为我的视图控制器创建一个TableView对象。

    public static TableView<BasicDataSet> renderTableFromBasicDataSets(ArrayList<BasicDataSet> sets) {

    TableView<BasicDataSet> tableView = new TableView<>();

    // create all keys required for the collection of basic data sets
    // and remove duplicates using a stream
    ArrayList<String> keys = new ArrayList<>();
    keys.add("name");
    keys.add("tagName");
    for(BasicDataSet basicDataSet : sets) {
        keys.addAll(basicDataSet.getDataPointKeys());
    }
    keys = new ArrayList<>(keys.stream().distinct().collect(Collectors.toList()));

    // create all required columns using keys to label column names
    // then declare their cellValueFactories
    for(String columnHeader : keys) {
        TableColumn<BasicDataSet, String> tempColumn = new TableColumn<>(columnHeader);
        tempColumn.setCellValueFactory(data -> {
            for(BasicDataSet set : sets) {
                if(columnHeader.equals("name")) {
                    return new ReadOnlyStringWrapper(set.getName());
                } else if(columnHeader.equals("tagName")) {
                    return new ReadOnlyStringWrapper(set.getTagName());
                } else {
                    final String tempVal = set.getDataPoint(columnHeader);
                    if(tempVal != null) {
                        return new ReadOnlyStringWrapper(set.getDataPoint(columnHeader));
                    } else {
                        return new ReadOnlyStringWrapper("");
                    }
                }
            }
            return new ReadOnlyStringWrapper("");
        });
        tableView.getColumns().add(tempColumn);
    }

    return tableView;
}


运行此代码时,仅呈现带有标题的列。没有数据显示。

我是Lambda函数的新手,因此非常感谢有关工厂的任何其他详细信息!

编辑:Here,您会在GitHub上找到一个小的示例项目。

最佳答案

您的单元格值工厂需要使用其data参数。该参数是TableColumn正在为其请求值的实际行数据。

忽略sets。您不应该查看所有数据,而只能查看由data表示的单行数据。

这意味着您的代码可以简单地删除for (BasicDataSet set : sets)循环,并可以从set获取data.getValue()

tempColumn.setCellValueFactory(data -> {
    BasicDataSet set = data.getValue();
    if (columnHeader.equals("name")) {
        return new ReadOnlyStringWrapper(set.getName());
    } else if (columnHeader.equals("tagName")) {
        return new ReadOnlyStringWrapper(set.getTagName());
    } else {
        final String tempVal = set.getDataPoint(columnHeader);
        if(tempVal != null) {
            return new ReadOnlyStringWrapper(set.getDataPoint(columnHeader));
        } else {
            return new ReadOnlyStringWrapper("");
        }
    }
});


理想情况下,您应该设计BasicDataSet类,使其以属性或其他可观察值的形式提供其数据,因此您的单元格值工厂不必继续创建临时的“非实体化”属性:

public class BasicDataSet {
    private final ReadOnlyStringWrapper name = new ReadOnlyStringWrapper();
    private final ReadOnlyStringWrapper tagName = new ReadOnlyStringWrapper();
    private final ObservableMap<String, String> dataPoints =
        FXCollections.observableHashMap();

    private final ObservableSet<String> keys =
        FXCollections.observableSet();

    public BasicDataSet(String name,
                        String tagName) {

        this.name.set(name);
        this.tagName.set(tagName);

        dataPoints.addListener(
            (MapChangeListener.Change<? extends String, ? extends String> c) -> {
            if (c.wasRemoved()) {
                keys.remove(c.getKey());
            }
            if (c.wasAdded()) {
                keys.add(c.getKey());
            }
        });
    }

    public ReadOnlyStringProperty nameProperty() {
        return name.getReadOnlyProperty();
    }

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

    public ReadOnlyStringProperty tagNameProperty() {
        return tagName.getReadOnlyProperty();
    }

    public String getTagName() {
        return tagName.get();
    }

    public ObservableMap<String> getObservableDataPoints() {
        return dataPoints;
    }

    public ObservableSet<String> getDataPointKeys() {
        return keys;
    }

    public StringBinding getObservableDataPoint(String key) {
        return Bindings.stringValueAt(dataPoints, key);
    }

    public String getDataPoint(String key) {
        return getObservableDataPoint(key).get();
    }
}


这使您可以将属性直接传递到单元格值工厂:

tempColumn.setCellValueFactory(data -> {
    BasicDataSet set = data.getValue();
    if (columnHeader.equals("name")) {
        return set.nameProperty();
    } else if (columnHeader.equals("tagName")) {
        return set.tagNameProperty();
    } else {
        return set.getObservableDataPoint(columnHeader);
    }
});

关于java - 具有HashMaps的类的TableColumn #setCellValueFactory,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57278359/

10-10 02:45