web-dev-qa-db-ja.com

カスタムオブジェクトを含むJavaFXカスタムセルファクトリ

カスタムListViewのリストに基づいて、カスタムCellで作られたカスタムobjectsを作成しようとしています。

カスタムオブジェクトはMessageというクラス名で、メッセージのいくつかのフィールドが含まれていますcontent受信者timestampおよびstatus (読み取り、送信など)。

この質問を見た後: FXMLを使用してJavaFXでListViewをカスタマイズ 私は無事に成功しました:

  1. カスタムセルでリストビューを作成し、セルデザインがFXMLファイル;
  2. controllerに関連付けられているため、各セルのデータをコレクションの現在の項目で埋めることができます。

ただし、両方をリンクできませんでした。ListViewの現在のアイテムにCell Controllerが送信されるようにする方法が見つからないようです。

これがセルファクトリーとリストビューの項目の充填の私のコードです。

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

そして今、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());
    }
}
_

ConversationCellControllerを表示することはできませんが、言えることは、これが(そのコンストラクターで)セルを設計するFXMLファイルをロードし、指定されたメッセージアイテムで値を入力できる場所です。

getView()メソッドは、現在塗りつぶされてデザインされたセルを含むルートペインを返します。

前に言ったように、設計は機能しますが、リストビューアイテムをCellFactoryにリンクできないようです。

protected void updateItem(Message item、boolean empty)

emptytrueに設定され、アイテムは確かにnull

これを機能させるにはどうすればよいですか?

12
Mackovich

updateItem(...)をオーバーライドするすべてのカスタムセル実装は、そのメソッドでセルが空の場合に対処する必要があります。だからあなたはこれの素朴な修正を行うことができます

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

ただし、これはパフォーマンスの観点からは良い解決策ではありません。空でないセルを使用してupdateItem(...)が呼び出されるたびにFXMLをロードしていますが、これはかなりコストのかかる操作です(ファイルI/Oが含まれる可能性があり、jarファイルからFXMLファイルを解凍し、ファイルを解析します)。多くのリフレクション、新しいUI要素の作成など)。ユーザーが数ピクセルずつリストビューをスクロールするたびに、FXアプリケーションスレッドがすべての作業を実行するように要求するのは望ましくありません。代わりに、セルはノードをキャッシュし、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);
        }
    }
}
_

ビューを更新する(ラベルにテキストを設定するなど)_ConversationCellControllersetItem(...)メソッドを定義する必要があります。

12
James_D