ページ

2013年5月14日火曜日

JavaFX - Custom Editable ListCell (1)

JavaFXのListViewで、表示内容をカスタマイズしたい場合は、ListCellを継承してカスタマイズしたい内容を実装し、ListViewのcellFactoryで、そのクラスのインスタンスを返すようにします。

javafx.scene.control.cellパッケージに、クラスライブラリで提供されているクラスがありますので、利用できるものがある場合は、これらを利用していくのが良いでしょう。これらのクラスは、forから始まるCallbackインターフェイスの実装を返すファクトリメソッドが用意されていますので、これをListViewのcellFactoryで設定するだけで利用できるようになっています。

例えば、文字列をリストで表示し、TextFieldで内容を編集したい場合は、TextFieldListCellを利用して、以下のようにListViewのcellFactoryで設定します。

listView.setCellFactory(TextFieldListCell.forListView());

また、以下のようにFXMLファイルに記述することもできます。

<ListView fx:id="listView" editable="true">
    <cellFactory>
        <TextFieldListCell fx:factory="forListView"/>
    </cellFactory>
</ListView>

単一の文字列を表示して、それをTextFieldやComboBox等で編集したい場合は、javafx.scene.control.cellパッケージで提供されているものを利用すれば良いのですが、複数の項目を表示したり、それらを編集できるようにしたい場合は、javafx.scene.control.cellパッケージで提供されているものでは対応できませんので、ListCellを継承して作成する必要があります。

ListCellを継承したクラスの実装としては、まず以下のメソッドをオーバーライドして、表示する内容について実装します。

void updateItem(T item, boolean empty)

updateItemメソッドの2番目の引数がtrueの場合は、このセルに表示するリストの内容がないことを表します。つまり、このセルに表示するリストの内容がない場合でもこのメソッドが呼び出されますので、2番目の引数の値に応じて、表示する内容を適切に実装する必要があります。また、スーパークラスでupdateItemの実装がされていますので、基本的には最初にスーパークラスのupdateItemメソッドを呼び出しておくのが良いでしょう。updateItemの実装例としては、以下のようになります。

@Override
protected void updateItem(T item, boolean empty) {
    super.updateImte(item, empty);

    if (empty) {
        // リストの内容がないときの表示内容を実装する。
        // 何も表示しない場合は、setGraphicメソッドとsetTextメソッドにnullを指定する。
        return;
    }

    // 引数のitemを利用して、表示する内容を実装する。
}

次に、編集を行う場合は、以下の3つのメソッドをオーバーライドして、編集に対する振る舞いを実装します。

void startEdit()
void cancelEdit()
void commitEdit(T newValue)

編集が開始された場合は、startEditメソッドが呼び出されます。このメソッドもupdateItemメソッドと同様に、スーパークラスでの実装がありますので、スーパークラスのstartEditメソッドを呼び出しておくのが良いでしょう。また、編集可能でない場合は、処理を行わにようにもしておきます。startEditの実装例としては、以下のようになります。

@Override
public void startEdit() {
    if (!isEditable()) { return; }
    if (!getListView().isEditable()) { return; }

    super.startEdit();

    // 編集開始時の処理を実装する。編集用のビューの設定等。
}

編集がキャンセルされた場合は、cancelEditメソッドが呼び出されます。このメソッドも同様に、スーパークラスでの実装がありますので、スーパークラスのcancelEditメソッドを呼び出しておくのが良いでしょう。また、編集中でない場合は、処理を行わないようにもしておきます。cancelEditの実装例としては、以下のようになります。

@Override
public void cancelEdit() {
    if (!isEditing()) { return; }

    super.cancelEdit();

    // 編集キャンセル時の処理を実装する。表示用のビューの設定等。
}

編集がコミットされた場合は、commitEditメソッドが呼び出されます。このメソッドも同様に、スーパークラスでの実装がありますので、スーパークラスのcommitEditメソッドを呼び出しておくのが良いでしょう。スーパークラスのcommitEditメソッドでは、updateItemメソッドが呼ばれ、updateItemのスーパークラスの実装では、編集中の場合はcancelEditメソッドを呼び出すようになっていますので、表示内容については特に実装する必要がありません。編集用のモデルの内容を、表示用のモデルに反映したい場合は、ここで実装します。また、編集中出ない場合は、処理を行わないようにもしておきます。commitEditの実装例としては、以下のようになります。

@Override
public void commitEdit(T newValue) {
    if (!isEditing()) { return; }

    supre.commitEdit(newValue);

    // 編集コミット時の処理を実装する。
}

次回は、上記の内容をふまえて、実際に編集可能なカスタムListCellを作成してみたいと思います。