Issue
I am learning the Cell and cell factory API's. I have read many examples and I can't wrap my head around how setCellFactory or setCellValuesFactory actually work.
Here are the examples in Scala (apologies Java users):
#1:
val cb = new javafx.util.Callback[ListView[Number], ListCell[Number]] {
override def call(list: ListView[Number]): ListCell[Number] = {
new MoneyFormatCell
}
}
#2:
class TranslationCell extends ListCell[String] {
override protected def updateItem(item: String, empty: Boolean) {
super.updateItem(item, empty)
textProperty().unbind()
if (empty || item == null) setText("") ?else textProperty().bind(createStringBinding(item))
}
}
Please ignore the different types and login within the Callback and the TranslationCell class, they aren't relevant in this case.
Now, if I do this, both options work:
x.setCellFactory(cb)
y.setCellFactory(lv => new TranslationCell)
I don't understand how or why the y
case works as the setCellFactory
takes a Callback[A]
and an instance of TranslationCell
which extends ListCell[B]
.
I also don't understand what the updateItem
method has to do with the function and how I can pass an instance of TranslationCell
to the setCellFactory
without any issues.
What's the relation between updateItem
and setCellFactory
?
Solution
The setCellFactory
method takes a Callback<ListView<T>,ListCell<T>>
, i.e. a function mapping a ListView<T>
to a ListCell<T>
. Nowhere in the code you posted do you pass a ListCell
to the setCellFactory
method.
The ListView
works internally by creating as many cells as it needs to display the visible content. Note that, since the ListView
is scrollable, this may be many fewer than the number of items contained in the ListView
. The ListCell
s are created by calling the Callback
passed to the setCellFactory()
method as many times as needed in order to create the number of cells needed. Typically, if the ListView
is large enough to display, for example, 10 cells, it will call the cell factory's Callback
at least 10 times (it may create one or two "spare" cells).
In order to actually display the content of the cells, the ListView
will call each cell's updateItem()
method, passing in the item to be displayed (or null
), and a boolean representing whether this cell is "empty". The implementation of the updateItem()
method should set the text and/or graphic of the cell based on the item
to be displayed.
At various points of a cell's lifespan, it may be asked to display a different item. For example, as the user scrolls around the ListView
, instead of creating new cells for the newly-displayed items and discarding the old ones (which would place a considerable strain on the garbage collector at some point), the ListView
will simply "reuse" the existing cells, asking them to display a different item instead. The actual implementation of this is (deliberately) not defined; all that you know is that the updateItem()
method will be called any time the cell needs to update its display.
Note that this means your updateItem()
method needs to handle all possibilities; it may go from empty to non-empty, from non-empty to empty, or from displaying one item to displaying a different item. Thus the updateItem()
method must set the text and/or graphic in any code path. If you do other things, such as change the style, you should again do so in any possible code path in the updateItem()
method.
Answered By - James_D
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)