TableViewでは、表示したい列を静的に定義して、表示するモデルのコレクションを指定して内容を表示しますが、今回は、表示したい列をモデルから動的に生成するユーティリティクラスを考えてみたいと思います。
このユーティリティクラスは、以下のようにスタティックプロパティでTableViewに指定すると、TableViewのitemsプロパティに値が設定されたときに、設定されたモデルの内容から、TableColumnを動的に作成して、TableViewに追加するようにします。
<TableView AutoTableColumnGeneration.enable="true"/>
まずは、クラス名をAutoTableColumnGenerationとして作成し、スタティックプロパティを定義します。
public final class AutoTableColumnGeneration {
private static final String AUTO_TABLE_COLUMN_GENERATION_ENABLE = "auto-table-column-generation-enable";
private static final ChangeListener<? super ObservableList> TABLE_VIEW_ITEMS_CHANGE_LISTENER = new ChangeListener<ObservableList>() {
@Override
public void changed(ObservableValue<? extends ObservableList> observableValue, ObservableList oldItems, ObservableList newItems) {
AutoTableColumnGeneration.generateTableColumns((TableView)((ReadOnlyProperty)observableValue).getBean(), newItems);
}
};
public static <S> boolean isEnable(TableView<S> tableView) {
Objects.requireNonNull(tableView);
if (!tableView.hasProperties()) { return false; }
Object enable = tableView.getProperties().get(AUTO_TABLE_COLUMN_GENERATION_ENABLE);
return enable != null && (boolean)enable;
}
public static <S> void setEnable(TableView<S> tableView, boolean enable) {
Objects.requireNonNull(tableView);
tableView.getProperties().put(AUTO_TABLE_COLUMN_GENERATION_ENABLE, enable);
if (enable) {
tableView.itemsProperty().addListener(TABLE_VIEW_ITEMS_CHANGE_LISTENER);
} else {
tableView.itemsProperty().removeListener(TABLE_VIEW_ITEMS_CHANGE_LISTENER);
}
}
private static void generateTableColumns(TableView tableView, ObservableList items) {
tableView.getColumns().clear();
if (items == null || items.isEmpty()) { return; }
...
}
}
TableViewのitemsプロパティに値が設定されたときに、TableColumnを生成するようにします。TableColumnの生成は、指定されたモデルに定義されているReadOnlyPropertyから生成するようにします。そこで、戻り値がReadOnlyPropertyに代入することができるメソッドをリフレクションで取得し、TableColumnのインスタンスを生成し、TableViewにそのインスタンスを追加するようにします。このとき、TableViewのeditableプロパティがtrueの場合に各項目が編集できるように、cellFactoryを設定しておきます。cellFactoryの設定は、取得したReadOnlyPropertyの種類によって、以下のようにします。
| Property | Cell | Converter |
|---|---|---|
| StringProperty | TextFieldTableCell | |
| BooleanProperty | CheckBoxTableCell | |
| IntegerProperty | TextFieldTableCell | IntegerStringConverter |
| LongProperty | TextFieldTableCell | LongStringConverter |
| FloatProperty | TextFiledTableCell | FloatStringConverter |
| DoubleProperty | TextFiledTableCell | DoubleStringConverter |
また、ObjectPropertyで、オブジェクトの型がDateの場合は、TextFieldTableCellをDateTimeStringConverterで、日付の書式を「yyyy/MM/dd HH:mm:ss」として生成するようにします。
上記以外の場合でも、cellFactoryを指定できるように、以下のメソッドを用意しておきます。
public static <S, T> void registerCellFactory(Class<T> cellValueClass, Callback<TableColumn<S, T>, TableCell<S, T>> cellFactory);
セルに設定する値の型をキーにして、cellFactoryを設定するようにします。
以上で、TableColumnを動的に作成することができますが、表示する列の順番は未定となり、また、各TableColumnの詳細の設定ができませんので、これらの設定ができるように、以下のアノテーションを定義しておきます。
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoTableColumn {
String id() default "";
String name() default "";
int order() default Integer.MAX_VALUE;
boolean editable() default true;
double prefWidth() default 80;
double maxWidth() default 5000;
double minWidth() default 10;
boolean resizable() default true;
boolean sortable() default true;
TableColumn.SortType sortType() default TableColumn.SortType.ASCENDING;
String[] styleClass() default "";
String[] cellStyleClass() default "";
}
TableColumnに設定することができるプロパティの値をこのアノテーションで指定できるようにします。AutoTableColumnGenerationでは、このアノテーションが指定されている場合は、設定されている値をTableColumnのプロパティにそれぞれ設定するようにします。ただし、orderについては、TableColumnの表示順を指定し、値の小さい順に表示するようにし、cellStyleClassについては、各セルに指定されているStyleClassを設定するようにします。
今回は、TableViewのTableColumnを動的に作成するユーティリティクラスについて考えてみました。次回は、このクラスを実際に使ってみたいと思います。