Custom JavaFX factory cell with custom objects

I am trying to create a custom ListView from a custom Cell based on a list of custom objects .

A custom object is the name of a class called Message , which contains several fields for the message Content , recipient , timestamp, and status (read, send, etc.).

Having looked at this question: Configure ListView in JavaFX using FXML I successfully:

  • created a ListView with custom cells , where the cell design is defined in the FXML file;
  • tied controller so that each cell data item can be filled with the current collection item;

However, I was unable to bind the two: I cannot find a way for the current ListView to send the Cell Controller .

Here is my code for the factory cell and populating ListView elements:

 final ObservableList observableList = FXCollections.observableArrayList(); observableList.setAll(myMessages); //assume myMessage is a ArrayList<Message> conversation.setItems(observableList); //the listview conversation.setCellFactory(new Callback<ListView<Message>, ListCell<Message>>() { @Override public ConversationCell<Message> call(ListView<Message> listView) { return new ConversationCell(); } }); 

And now the ConversationCell class:

 public final class ConversationCell<Message> extends ListCell<Message> { @Override protected void updateItem(Message item, boolean empty) { super.updateItem(item, empty); ConversationCellController ccc = new ConversationCellController(null); setGraphic(ccc.getView()); } } 

I cannot show the ConversationCellController, but all I can say is where (in its constructor) I load the FXML file that the cell designs, and then I can fill in the values ​​with this message.

The getView() method returns the root panel , which contains a cell with an already filled and constructed structure.

As I said, the project work, but I can not associate ListView elements with CellFactory , because in the method

protected void updateItem (message element, boolean empty)

empty set to true , and the item is really null .

What can I do to make this work?

+7
java listview javafx custom-cell
source share
1 answer

All custom cell implementations that override updateItem(...) must deal with the case when the cell is empty in this method. So you can make a naive fix for this with

 public final class ConversationCell<Message> extends ListCell<Message> { @Override protected void updateItem(Message item, boolean empty) { super.updateItem(item, empty); if (empty) { setGraphic(null); } else { // did you mean to pass null here, or item?? ConversationCellController ccc = new ConversationCellController(null); setGraphic(ccc.getView()); } } } 

However, this is not a good solution in terms of performance. You load FXML every time updateItem(...) is called with a non-empty cell, and that is a rather expensive operation (potentially related to a file file, unpacking the FXML file from the jar file, parsing the file, a lot of reflection, creating new interface elements, etc. d.). You do not want the application flow of applications to perform all these actions each time the user scrolls the list view by a few pixels. Instead, your cell should cache the node and should update it in the updateItem method:

 public final class ConversationCell<Message> extends ListCell<Message> { private final ConversationCellController ccc = new ConversationCellController(null); private final Node view = ccc.getView(); @Override protected void updateItem(Message item, boolean empty) { super.updateItem(item, empty); if (empty) { setGraphic(null); } else { ccc.setItem(item); setGraphic(view); } } } 

You must define the setItem(...) method in the ConversationCellController that updates the view (sets text on shortcuts, etc., etc.) accordingly.

+5
source share

All Articles