我在JavaFX应用程序中使用ListView
。列表中的项目需要的不仅仅是一个字符串才能显示它们,因此我制作了ListCell<T>
的自定义实现,其中T
是我正在显示的对象的类。在此自定义类中,我在构造函数中创建BorderPane
并覆盖updateItem(T item, boolean empty)
。我的想法是,当调用updateItem
时,我将单元格的图形设置为BorderPane,同时更改其中Label
的一些属性。但是,我注意到updateItem
未被调用一次(例如,当通过滚动回收单元格或添加新项目时),但它始终被称为 ,例如当焦点从一个单元格变为另一个单元格时(即使没有滚动),或者调整场景大小,或者按下borderpane中的按钮时,......
我需要ListView
使用自定义ListCell
。我想在重用单元格时接收一个回调,传递新项目作为参数呈现。然后我想使用该项作为模型来构造一个视图 - 控制器对,我将其视图并将其用作单元格的graphic
。此视图中的按钮和其他控件应该可以工作。这在JavaFX中是否可行?
链接问题:
updateItem
)答案 0 :(得分:9)
基本思想是很少构建单元格,但updateItem(...)
方法可能会被频繁调用。没有实际保证该项目在updateItem(...)
的调用之间确实发生了变化。 updateItem(...)
的默认实现负责处理选择,焦点等,因此如果任何属性发生更改(即使项目未更改),则可能需要调用此方法。
因此,您应该努力减少updateItem(...)
方法的开销。目前尚不清楚多次频繁的通话会阻止您做您想做的事情(例如,当您将新项目作为参数传递给您的模型时,请检查它是否与您的模型完全不同你在做任何更新之前已经有了。)
我认为updateItem(...)
确实有些错误名称:它不仅在item
更新时被调用,而且在任何时候都需要更新单元格。已经有一种机制只有在item
发生变化时才能执行代码:只需向单元格itemProperty()
注册一个监听器。您可以使用此技术(我通常更喜欢)来创建不同样式的ListCell
:
ListView<...> listView = ... ;
listView.setCellFactory(lv -> {
BorderPane cellRoot = new BorderPane();
// create nodes, register listeners on them, populate cellRoot, etc...
ListCell<...> cell = new ListCell<>();
cell.itemProperty().addListener((obs, oldItem, newItem) -> {
if (newItem != null) {
// update cellRoot (or its child nodes' properties) accordingly
}
});
cell.emptyProperty().addListener((obs, wasEmpty, isEmpty) -> {
if (isEmpty) {
cell.setGraphic(null);
} else {
cell.setGraphic(cellRoot);
}
});
cell.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
return cell ;
});
这种方法在您的方案中可能会更好。
答案 1 :(得分:0)
我刚刚开始使用JavaFX而且我无法解释其工作原理的所有细节(它在新项目和现有项目上调用方法),但我解决问题的方法是简单地调用myContainer.getChildren().removeAll( ... )
在我的ListCell public class MyCell extends ListCell<MyContent>
的实现中,我创建了许多不同的项目并将它们添加到容器中,该容器在我的列表视图中成为一行。所以,在我将它们添加回来之前,我只需要从该容器中删除相同的项目。这是我所做的简化版本。似乎工作得很好。我确实尝试过James_D的建议,但它对我不起作用并产生同样的错误。
@Override
public void updateItem(MyContent item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty == true) {
setGraphic(null);
setText(null);
} else {
// here I user the "item" to decide how to create
// objects a, b, c ... which are Rectangle, Label and Label
// I also update myMainContainer, which is a Pane
myMainContainer.getChildren().removeAll(a, b, c);
myMainContainer.getChildren().addAll(a, b, c);
setGraphic(myMainContainer);
}
}