我正在编写一个使用JavaFX8 TreeTableView的应用程序。树表有三列,其中两列是字符串属性(名称和值),另一列有一个Canvas小部件,用于从a中的数据中绘制图片数据库(波形)。在应用程序上还有一个控件,允许(所有图纸的)显示被缩小或缩小(或者左右滚动)。
name 和 value 列使用我的数据模型中的StringProperty值,因此为这些列设置了CellValueFactory。绘图列使用CellFactory和CellValueFactory,如下所示:
// Waveform column
TreeTableColumn<DrawRow, WaveformTraceBox> waveColumn = new TreeTableColumn<>();
waveColumn.setCellFactory(new Callback<TreeTableColumn<DrawRow, WaveformTraceBox>, TreeTableCell<DrawRow, WaveformTraceBox>>() {
@Override
public TreeTableCell<DrawRow, WaveformTraceBox> call(TreeTableColumn<DrawRow, WaveformTraceBox> param) {
return new WaveformTraceBoxTreeTableViewCell<>();
}
});
waveColumn.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<DrawRow, WaveformTraceBox>, ObservableValue<WaveformTraceBox>>() {
@Override
public ObservableValue<WaveformTraceBox> call(TreeTableColumn.CellDataFeatures<DrawRow, WaveformTraceBox> param) {
return new ReadOnlyObjectWrapper<>(new WaveformTraceBox());
}
});
WaveformTraceBoxTreeTableViewCell是:
protected static class WaveformTraceBoxTreeTableViewCell<T> extends TreeTableCell<DrawRow, T> {
public WaveformTraceBoxTreeTableViewCell() {
super();
}
@Override
protected void updateItem(T value, boolean empty) {
super.updateItem(value, empty);
setText(null);
setGraphic(null);
if (!empty && getTreeTableRow().getItem() != null) {
getTreeTableRow().getItem().setTraceBox((WaveformTraceBox)value);
setGraphic((WaveformTraceBox) value);
}
}
DrawRow是我的数据模型。当用户通过窗口上的控件缩小或缩小时,绘图行模型将通知其关联的Canvas绘图项目以重新绘制其显示。显示图的绘制可能需要一些时间,因为需要处理大量数据才能生成显示。
现在我的问题:当滚动TreeTableView小部件时,它将要求新的Canvas小部件 - 它与数据模型中的DrawRow项相关联。但是,从列表中滚动的窗口小部件将被树窗口小部件抛弃。
我发现无法判断我正在使用的物品是否已被丢弃或是否已被使用。因此,代码正在做更多的工作,因为它试图绘制不再使用或显示的单元格。最终,由于我认为垃圾收集会导致其他问题。
所以我真正的问题是如何判断一个单元格是否已被树表放弃,以便我可以停止尝试更新它?任何帮助都将非常感激。我无法在我所做的各种网络搜索中找到它。
答案 0 :(得分:0)
无论如何,你的结构很奇怪。
首先,(不太重要)为什么你的WaveformTraceBoxTreeTableViewCell
是通用的?当然你想要
protected static class WaveformTraceBoxTreeTableViewCell extends TreeTableCell<DrawRow, WaveformTraceBox>
然后你可以用T
替换WaveformTraceBox
并摆脱演员表等。
第二:如果我理解正确,WaveformTraceBox
是某种自定义Node
子类;即它是一个UI组件。单元格值工厂不应该真正返回UI组件 - 它应该返回要显示的数据。然后,单元工厂应使用一些UI组件来显示数据。
这样,您可以在单元格实现中创建一个WaveFormTraceBox,并更新它在updateItem(...)
方法中显示的数据。
类似于:
// Waveform column
TreeTableColumn<DrawRow, WaveformData> waveColumn = new TreeTableColumn<>();
waveColumn.setCellFactory(new Callback<TreeTableColumn<DrawRow, WaveformData>, TreeTableCell<DrawRow, WaveformData>>() {
@Override
public TreeTableCell<DrawRow, WaveformData> call(TreeTableColumn<DrawRow, WaveformData> param) {
return new WaveformTraceBoxTreeTableViewCell();
}
});
waveColumn.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<DrawRow, WaveformData>, ObservableValue<WaveformData>>() {
@Override
public ObservableValue<WaveformTraceBox> call(TreeTableColumn.CellDataFeatures<DrawRow, WaveformTraceBox> param) {
return new ReadOnlyObjectWrapper<>(getDataToDisplayForItem(param.getValue()));
}
});
protected static class WaveformTraceBoxTreeTableViewCell extends TreeTableCell<DrawRow, WaveFormData> {
private WaveformTraceBox traceBox = new WaveformTraceBox();
public WaveformTraceBoxTreeTableViewCell() {
super();
}
@Override
protected void updateItem(WaveFormData value, boolean empty) {
super.updateItem(value, empty);
setText(null);
setGraphic(null);
if (!empty && getTreeTableRow().getItem() != null) {
traceBox.setData(value);
setGraphic(traceBox);
} else {
setGraphic(null);
}
}
}
显然,您需要定义WaveFormData类来封装WaveFormTraceBox
将显示的数据,并为WaveFormTraceBox
提供setData(WaveFormData)
方法。如果您正在使用需要清理的任何资源,则setData(...)
的调用将指示WaveformTraceBox
不再访问先前的数据。