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を動的に作成するユーティリティクラスについて考えてみました。次回は、このクラスを実際に使ってみたいと思います。