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が返ります。