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