JavaFXのTableViewで列数を動的に生成する方法
以前、JavaFXのTableVeiwの使い方について書きましたが、この方法の問題として列数が固定されてしまうという点です。データクラスとリンクさせるためデータクラスのインスタンス変数で決まってしまうからです。
そうではなく、任意のCSVファイルを読み込む場合など、列数や列名がデータの都度可変させるにはどうすれば良いか、というのが今回のテーマです。
[ad#top-1]
完成形
完成形はこちらです。列が3つありますが、これはプログラムの中で動的に生成しているものです。データクラスと関連付けしていません。
SceneBuilderでも特に列(TableColmun)を貼り付けてはいません。TableView本体のみです。
ソースコード全文
まずはデータクラスのソースコードです。ArrayListでデータリストを保持しますが、この要素数が列の数になります。肝はStringProperty get(int index)
メソッドで、これを使って各列とArrayListの要素No.とを対比させます。
import java.util.*; import javafx.beans.property.*; public class User { private ArrayList<String> list; public User(ArrayList<String> list) { this.list = list; } public void add(String data){ list.add(data); } public StringProperty get(int index){ return new SimpleStringProperty(list.get(index)); } }
次に本体のソースコードです。
import javafx.application.Application; import javafx.fxml.*; import javafx.scene.Scene; import javafx.stage.Stage; import javafx.scene.layout.*; import javafx.event.ActionEvent; import javafx.scene.control.*; import javafx.collections.*; import javafx.scene.control.cell.*; import javafx.scene.control.TableColumn.*; import java.util.*; import javafx.util.*; import javafx.beans.value.*; import javafx.beans.property.*; public class TableTest2 extends Application implements Initializable { @FXML private TableView table; private List<TableColumn> columnList; private ObservableList<User> data; public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) throws Exception{ VBox root = FXMLLoader.load(getClass().getResource("TableTest2.fxml")); stage.setTitle("TableView Test"); stage.setScene(new Scene(root)); stage.show(); } @Override public void initialize(java.net.URL url, java.util.ResourceBundle bundle) { columnList = new ArrayList<TableColumn>(); TableColumn dateCol1 = new TableColumn("名前"); columnList.add(dateCol1); TableColumn dateCol2 = new TableColumn("住所"); columnList.add(dateCol2); TableColumn dateCol3 = new TableColumn("年齢"); columnList.add(dateCol3); table.getColumns().addAll(columnList); dateCol1.setCellValueFactory(new Callback<CellDataFeatures<User, String>, ObservableValue<String>>() { public ObservableValue<String> call(CellDataFeatures<User, String> p) { return p.getValue().get(0); } }); dateCol2.setCellValueFactory(new Callback<CellDataFeatures<User, String>, ObservableValue<String>>() { public ObservableValue<String> call(CellDataFeatures<User, String> p) { return p.getValue().get(1); } }); dateCol3.setCellValueFactory(new Callback<CellDataFeatures<User, String>, ObservableValue<String>>() { public ObservableValue<String> call(CellDataFeatures<User, String> p) { return p.getValue().get(2); } }); data = FXCollections.observableArrayList(); table.itemsProperty().setValue(data); table.setItems(data); ArrayList<String> col = new ArrayList<String>(); col.add("鈴木太郎"); col.add("東京"); col.add("34"); data.addAll( new User(col) ); } }
ポイントは以下の部分です。列数固定の場合はsetCellValueFactory
の引数にデータクラスのインスタンス変数名をあてがっていましたが、今回は以下のようにCallback
クラスを使います。
return p.getValue().get(0);
のget
メソッドは、先ほどのUserクラスのStringProperty get(int index)
メソッドです。
dateCol1.setCellValueFactory(new Callback<CellDataFeatures<User, String>, ObservableValue<String>>() { public ObservableValue<String> call(CellDataFeatures<User, String> p) { return p.getValue().get(0); } });
以下のJavaの公式ヘルプページの「プロパティを含まないクラスに対するTableViewのサポート」に解説が書かれているので参照してください。
今回の方法を使えば、例えばcsvファイルを読み込んで先頭の項目行からTableViewの列を生成して2行目以下のデータを読み込む、という方法が可能になります。
[ad#ad-1]
スポンサーリンク