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]
スポンサーリンク




