Pregunta Fábrica de células personalizadas JavaFX con objetos personalizados


Estoy tratando de tener una costumbre ListView hecho de encargo Cell basado en una lista de personalizados objects.

El objeto personalizado es el nombre de clase llamado Message que contiene algunos campos para el mensaje contenido, recipiente, marca de tiempo y estado (leer, enviar etc.).

Después de mirar esta pregunta: Personalice ListView en JavaFX con FXML Tengo éxito:

  1. creado un ListView con celdas personalizadas donde el diseño de la celda se define en una Archivo FXML ;
  2. asociado a controlador para que cada celda de datos se pueda completar con el elemento actual de la colección;

Sin embargo, no pude vincular ambos: parece que no puedo encontrar la forma de enviar el elemento actual de ListView Controlador de celda.

Aquí está mi código para la fábrica de células y el llenado de artículos ListView:

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

Y ahora, la clase 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());
    }
}

No puedo mostrar el ConversationCellController, pero todo lo que puedo decir es que aquí (en su constructor) cargo el archivo FXML que diseña la celda y luego puedo completar los valores con el ítem Message dado.

los getView() método devuelve el panel raíz que contiene la celda ahora llena y diseñada.

Como dije anteriormente, el trabajo de diseño, pero parece que no puedo vincular los elementos ListView con el CellFactory porque en el método

protected void updateItem (elemento de mensaje, booleano vacío)

vacío se establece en cierto y el artículo es de hecho nulo.

¿Qué puedo hacer para que esto funcione?


8
2018-01-17 12:33


origen


Respuestas:


Todas las implementaciones de celdas personalizadas que anulan updateItem(...) Necesito lidiar con el caso donde la celda está vacía en ese método. Así que podrías hacer una ingenua solución de esto con

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

Sin embargo, esta no es una buena solución desde el punto de vista del rendimiento. Usted está cargando el FXML todo el tiempo updateItem(...) se llama con una celda no vacía, y eso es una operación bastante costosa (potencialmente involucrando archivo E / S, descomprimir el archivo FXML de un archivo jar, analizar el archivo, mucha reflexión, crear nuevos elementos UI, etc.). No desea pedirle al subproceso de la aplicación FX que haga todo ese trabajo cada vez que el usuario desplaza la vista de lista unos pocos píxeles. En cambio, su celda debe almacenar en caché el nodo y debe actualizarlo en el updateItem método:

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

Debes definir un setItem(...) método en el ConversationCellController que actualiza la vista (establece el texto en las etiquetas, etc, etc.) en consecuencia.


7
2018-01-17 14:32