我正在尝试在JavaFX中实现一个TreeTableView,其中包含' MyData'对象,并有两列。第一列应包含一个字符串;这很简单:
column1.setCellValueFactory((TreeTableColumn.CellDataFeatures<MyData, String> entry)
-> new ReadOnlyStringWrapper(entry.getValue().getValue().toString()));
对于第二列,我需要在MyData对象中使用一些更复杂的数据,我想基本上渲染一系列描绘该数据的图标。所以,我尝试创建一个自定义单元格渲染器:
MyCellRenderer extends TreeTableCell<MyData, MyData> {
@Override
protected void updateItem(MyData item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
setText(null);
} else {
// building some ContentPane with an HBox of Images here..
setGraphic(contentPane);
}
}
}
然后按如下所示设置CellFactory和CellValueFactory列:
column2.setCellValueFactory((TreeTableColumn.CellDataFeatures<MyData, MyData> entry)
-> new ReadOnlyObjectWrapper(entry));
column2.setCellFactory(param -> new MyCellRenderer());
但是我在运行时得到了这个异常:
线程中的异常&#34; JavaFX应用程序线程&#34; java.lang.ClassCastException: javafx.scene.control.TreeTableColumn $ CellDataFeatures无法强制转换 到MyData
我担心我并不真正理解所有这些类的不同泛型类型的含义,而且我也不确定&#34; ReadOnlyObjectWrapper&#34;。我只是尝试从第一列的设置中复制/粘贴和调整它。
如果有人能对我有所启发,我将非常感激。不幸的是,关于TreeTableView的oracle文档没有详细介绍,只是展示了简单的例子。
谢谢
答案 0 :(得分:1)
你需要
column2.setCellValueFactory((TreeTableColumn.CellDataFeatures<MyData, MyData> entry)
-> new ReadOnlyObjectWrapper<>(entry.getValue().getValue()));
请注意,如果您不使用原始类型(即使用ReadOnlyObjectWrapper<>
或ReadOnlyObjectWrapper<MyData>
而不只是ReadOnlyObjectWrapper
),编译器会通知您错误,这很多比试图破解运行时出错的东西更好。
如您所见,单元格值工厂的参数类型为TreeTableColumn.CellDataFeatures
(请参阅docs)。这只是行值的包装器,您将从中提取单元格中显示的数据;这个包装器只包含行本身的树项(使用getValue()
获得),以及单元格值工厂所附加的列(getTreeTableColumn()
)以及该列所属的表属于(getTreeTableView()
)。
我认为,后两者旨在使您能够编写一般的,可重复使用的单元值工厂,您可能希望根据它们所附加的列或表来自定义它们。 (用例对我来说很难设想,但我怀疑他们有一些机会...)
包含行的TreeItem
(您使用entry.getValue()
获得的行)当然包含行值(您可以使用getValue()
获取此行,这就是为什么您最终会遇到{ {1}}),以及其他entry.getValue().getValue()
特定信息(扩展,选择等等)。
答案 1 :(得分:1)
您将entry
类型TreeTableColumn.CellDataFeatures<MyData, MyData>
作为初始值传递给新的ReadOnlyObjectWraper
- 原始类型 - 期望类型为{{1在运行时而不是MyData
。如您所见,泛型类型不匹配。
尝试更改
TreeTableColumn.CellDataFeatures<MyData, MyData>
到
new ReadOnlyObjectWrapper(entry)
两次new ReadOnlyObjectWrapper<>(entry.getValue().getValue())
来电的原因是因为第一个getValue()
返回entry.getValue()
而第二个TreeItem<MyData>
返回实际的getValue()
个实例。
这是假设您的表已声明为MyData
并且您的列已声明为TreeTableView<MyData>
。
编辑:由于您说您不太了解所有通用签名,因此这里有一个简短的解释。
TreeTableColumn<MyData, MyData>
此处TreeTableView<S>
是S
显示的对象类型。 AKA,模型类。一个示例是TreeTableView
类,它会使Person
成为S
。
Person
此处的TreeTableColumn<S, T>
与S
中S
的{{1}}相同,该列必定是该列的一部分。 TreeTableView
是列中T
将显示的对象类型。这通常是类型TreeTableCell
的属性中包含的值。例如S
的{{1}}名称会使StringProperty
成为Person
。
T
String
和TreeTableCell<S, T>
将与该单元格所属的S
相同。
现在,对于值回调:
T
同样,TreeTableColumn
和Callback<TreeTableColumn.CellDataFeatures<S, T>, ObservableValue<T>>
代表S
所属的T
相同类型。此TreeTableColumn
返回包含Callback
类型的Callback
,以便ObservableValue
可以观察更改的值并相应地更新UI。在您的情况下,由于您要显示的类型不在属性中,因此您返回新的T
以满足API要求。如果我继续使用上面提到的名称TreeTableCell
,您最终会得到类似的结果:
ReadOnlyObjectWrapper