I'm using a ListView
in a JavaFX application. The items in the list require more than just a string to display them so I made a custom implementation of ListCell<T>
, where T
is the class of the objects I'm displaying. In this custom class, I create a BorderPane
in the constructor and override updateItem(T item, boolean empty)
. The idea was that when updateItem
is called, I set the graphic of the cell to be the BorderPane while change some properties of Label
s inside of it. However, I noticed updateItem
is not called once (e.g. when a cell is recycled through scrolling or a new item is added), but it is called all the time, e.g. when the focus changes from one cell to another (even without scrolling), or when the scene is resized, or when a button inside the borderpane is pressed, ...
I need to have a ListView
with custom ListCell
s. I want to receive one callback when a cell is reused, passing the new item to be rendered as a parameter. Then I want to use that item as a model to construct a view-controller pair of which I take the view and use it as the graphic
of the cell. Buttons and other controls inside this view should work. Is this possible in JavaFX?
Linked problem:
updateItem
)The basic idea is that cells are constructed rarely but the updateItem(...)
method is likely to be called frequently. There is no actual guarantee that the item has really changed between calls to updateItem(...)
. The default implementation of updateItem(...)
takes care of handling selection, focus, etc, so this method probably needs to be invoked if any of those properties change (even if the item has not changed).
You should therefore strive to reduce the overhead of the updateItem(...)
method. It's not clear that multiple, frequent calls would prevent you doing what you want (for example, when you pass the new item as a parameter to your model, check to see if it's really different to the one you already have before doing any updates).
I'd argue that updateItem(...)
is really somewhat misnamed: it's called not only when the item
is updated, but really any time the cell might need to be updated. There's already a mechanism for executing code only when the item
changes though: just register a listener with the cell's itemProperty()
. You can use this technique (which I generally prefer) to create a different style of 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 ;
});
This approach may work better in your scenario.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With