Usine de cellules personnalisées JavaFX avec des objets personnalisés


J'essaie d'avoir un ListView personnalisé fait de Cell personnalisé basé sur une liste de objects personnalisé.

L'objet personnalisé est un nom de classe appelé Message, qui contient quelques champs pour que le message contenu, destinataire, timestamp et statut (lu, envoyé etc.).

Après avoir regardé cette question : Personnaliser ListView dans JavaFX avec FXML j'ai réussi :

  1. a créé une vue de liste avec cellules personnalisées où la conception de cellule est définie dans un fichier FXML;
  2. associé un controller{[11] } afin que chaque donnée de cellule puisse être remplie avec l'élément courant de la collection;

Cependant, j'ai échoué à lier les deux : je n'arrive pas à trouver un moyen pour que l'élément actuel de ListView soit envoyé auCell Controller .

Voici mon code pour l'usine de cellules et le remplissage ListView des éléments:

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();
    }
});

Et maintenant, la classe ConversationCell :

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());
    }
}

Je ne peux pas afficher le ConversationCellController mais tout ce que je peux dire, c'est là (dans son constructeur) que je charge le fichier FXML qui conçoit la cellule, puis je peux remplir les valeurs avec l'élément de message donné.

La méthode getView()renvoie le volet racine qui contient la cellule maintenant remplie et conçue.

Comme je l'ai dit précédemment, la conception fonctionne, mais je n'arrive pas à lier les éléments ListView avec leCellFactory car dans la méthode

Protected void updateItem(Élément de message, booléen vide)

Vide est définie sur true et le point est, en effet, null.

Que puis-je faire pour que cela fonctionne ?

Author: Community, 2016-01-17

1 answers

Toutes les implémentations de cellules personnalisées qui remplacent updateItem(...) doivent traiter le cas où la cellule est vide dans cette méthode. Donc, vous pourriez faire une correction naïve de cela avec

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());
        }
    }
}

Cependant, ce n'est pas une bonne solution du point de vue de la performance. Vous chargez le FXML chaque fois que updateItem(...) est appelé avec une cellule non vide, et c'est une opération assez coûteuse (impliquant potentiellement des e/s de fichier, décompressant le fichier FXML d'un fichier jar, analysant le fichier, beaucoup de réflexion, créant nouveaux éléments d'interface utilisateur, etc.). Vous ne voulez pas demander au thread d'application FX de faire tout ce travail chaque fois que l'utilisateur fait défiler la vue de liste de quelques pixels. Au lieu de cela, votre cellule doit mettre en cache le nœud et le mettre à jour dans la méthode updateItem:

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);
        }
    }
}

Vous devez définir une méthode setItem(...) dans le ConversationCellController qui met à jour la vue (définit le texte sur les étiquettes, etc.) en conséquence.

 7
Author: James_D, 2016-01-17 14:32:36