プロジェクト

全般

プロフィール

JavaFXと表(TableView)

TableViewに関する資料

Oracle公式ドキュメント

JavaFX Working with JavaFX UI Components - Table View
JavaFX: JavaFX UIコンポーネントの操作 - 表ビュー

記事、ブログ、等

JavaFX 8 Tutorial - Part 2: Model and TableView
JavaFX 2で始めるGUI開発 第5回 リスト、コンボボックス、テーブル(5/7)

過去に書いたTableViewの使い方

JavaFX 2のTableViewを使うメモ
JavaFXのTableViewをScene Builderで作成
TableViewで既に行として表示済みのデータの列を更新する際の注意点

使い方メモ

TableViewの設置例

  • 表形式で表示するデータクラスを定義
  • TableViewを配置
  • TableColumnを配置
  • コントローラークラスにTableView, TableColumnのフィールドを定義
  • 各TableColumnとデータクラスのデータ要素を紐付け
  • TableViewとデータクラスのリストを紐付け

データクラスの定義

JavaFXのプロパティをフィールドに持つデータクラスを定義します。
例として、整数型のID、文字列型のNameを持つMyDataクラスを次に示します。

public class MyData {
    private IntegerProperty idProperty = new SimpleIntegerProerty();
    private StringProperty nameProperty = new SimpleStringProperty();

    public MyData(int id, String name) {
        idProperty.set(id);
        nameProperty.set(name);
    }

    public IntegerProperty idProperty() {
        return idProperty;
    }
    public StringProperty nameProperty() {
        return nameProperty;
    }
}

TableColumnに紐付けるために、データクラスにJavaFXプロパティ型のフィールドを設け、プロパティを取り出すメソッドを定義します。

  • JavaFXのプロパティ型でなく、通常のデータ型のフィールドとgetメソッドを定義しても表示できますが、その場合はデータの値が変更されても表の表示にデータの値の変更を反映することはできません。

レイアウト(配置)

TableViewコントロールは、スクロール機能がついているので、単独で任意のコンテナに配置します。
TableViewは、列ごとにTableColumnを子要素として持ちます。

SceneBuilderでTableViewを配置、子要素にTableColumnが2つある例です。

コントローラーのフィールドにTableViewとTableColumnを定義

public class MyController implements Initializable {
    :
    @FXML
    private TableView<MyData> table;  // ①
    @FXML
    private TableColumn<MyData, Integer> idColumn;  // ②
    @FXML
    private TableColumn<MyData, String> nameColumn;  // ②
    :
}
  • ①型パラメータに、表のレコード(行)を表現するデータクラスを指定してTableViewのフィールドを宣言
  • ②型パラメータに、①のクラスと、その列のデータの型を指定してTableColumnのフィールドを宣言

FXMLファイルのfx:idにフィールド名を指定

Scene Builderで、FXMLのTableViewおよびTableColumnのfx:idに、コントローラーのフィールド名を設定します。

TableColumnとデータクラスのデータ要素を紐付け

public class MyController implements Initializable {
    :
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        idColumn.setCellValueFactory(new PropertyValueFactory<MyData, Integer>("id"));
        nameColumn.setCellValueFactory(new PropertyValueFactory<MyData, String>("name"));
    }
    :
}
setCellValueFactoryにPropertyValueFactoryを設定

TableColumn の setCellValueFactoryメソッドに、テーブルに設定するデータ型(MyData)とそのカラムに表示するデータ型(IntegerやString)を型パラメータとして指定したPropertyValueFactoryを指定します。PropertyValueFactoryのコンストラクタには、テーブルに設定したデータ型のプロパティ名を文字列で指定します。

com.sun.javafx.property.PropertyReferenceの実装より

  • プロパティ名(例:name)に対応するゲッターメソッド(例:getName)がデータクラスにあればこれを使用
  • ゲッターメソッドがない場合、プロパティ名(例:name)に対応するプロパティ取得メソッド(例:nameProperty)を使用
ラムダ式でセルの値を取得

PropertyValueFactoryは、テーブルに設定するデータ型に、特定の命名規則に沿ったゲッターメソッドが用意されていることが前提となります。また、文字列でプロパティ名を指定するのでタイプミスによるバグが入りやすい(コンパイラがチェックできない)、record型のゲッターメソッド名には対応できないというデメリットがあります。
そのような時は、ラムダ式でデータを取得するロジックを指定します。

public class MyController implements Initializable {
    :
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        idColumn.setCellValueFactory(p -> p.getData().idProperty());
        nameColumn.setCellValueFactory(p -> p.getData().nameProperty());
    }
    :
}

データの型がProperty型ではない場合、CellValueFactoryはセルの値をProperty型で返す必要があるので、ReadyOnlyXxxWrapperでデータの値を包みます。

        someValueColumn.setCellValueFactory(p -> new ReadOnlyIntegerWrapper(p.getData().getSomeValue()));

TableViewとデータクラスのリストを紐付け

TableViewインスタンスは表示するデータのリストを内蔵していますが、ビューとデータを分離する設計原則に合わせて、モデルクラスのインスタンスにデータクラスのリストを設置し、このリストをTableViewと紐付けします。

TableViewと紐付けるリストは、ObservableArrayListなどを使用します。

public class MyModel {
    private final ObservableList<MyData> data = FXCollections.observableArrayList();    
    :
    public ObservableList<MyData> getMyDataList() {
        return data;
    }
}

コントローラークラスで紐付けます。

public class MyController implements Initializable {
    private final MyModel model = ...
    :
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        table.itemProperty().setValue(model.getMyDataList());
        :
    }
    :
}

セルの表示のカスタマイズ

TableColumnには、cellFactoryとcellValueFactoryが備わっており、セルの見栄えや編集可能なセルなどの振る舞いをcellFactoryで設定、セルに表示するデータの取得方法をcellValueFactoryで設定します。

cellFactoryでカスタマイズする方法

TableColumnクラスのsetCellFactory(シグニチャは次)で、TableCellのインスタンスを生成するCallBackを渡します。

public final void setCellFactory(Callback<TableColumn<S,T>,TableCell<S,T>> value)

次は、整数型のデータを持つTableColumnで整数の16進数文字列(接頭辞に0xを付加)を表示する例を示します。

        idColumn.setCellFactory(col -> new TableCell<MyData, Integer>() {
            @Override
            protected void updateItem(Integer item, boolean empty) {
                super.updateItem(item, empty);
                if (empty || item == null) {
                    return;
                }
                setText(String.format("0x%x", item));
            }
        });

セルに表示する文字列は、TableColumnに紐づくcellFactoryにTableCellのサブクラスを生成させるようにします。TableCellのサブクラスは、updateItemメソッドでセルに表示するデータを受け取り、文字列をsetTextメソッドで設定します。
TableCellはお作法として、オーバーライドしたupdateItemでまずsuper.updateItemを呼び出し、次にセルが空あるいは表示するデータがない時の処理と、値が渡された時の処理を記載します。

  • 似たようなTableCellを複数のTableColumnで使うならばクラス化したほうが良いかもしれません。

cellValueFactoryでカスタマイズする方法

TableColumnクラスのsetCellValueFactory(シグニチャは次)で、ObserbableValueを生成するCallBackを渡します。

public final void setCellValueFactory(Callback<TableColumn.CellDataFeatures<S,T>,ObservableValue<T>> value)

次は、整数型のデータを持つTableColumnで整数の16進数文字列(接頭辞に0xを付加)を表示する例を示します。

        idColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<MyData, String>, ObservableValue<String>>() {
            @Override
            public ObservableValue<String> call(TableColumn.CellDataFeatures<TimetagVcdu, String> param) {
                return new ReadOnlyStringWrapper(String.format("0x%x", param.getValue().getId()));
            }
        });

TableColumnに紐づくcellValueFactoryに、表のデータクラスから値を取得し文字列のPropertyを返すCallbackを設定します。

スクロール

現在表示している行の範囲を知るには?

  • TableViewのgetSelectionModelに、getSelectedIndexまたはgetFocusedIndexを問い合わせると、テーブルの特定のセルを明示的に選択していない場合、前者は-1が、後者は0が返ります。


18日前に更新