2014年02月05日(水) [長年日記]
■ [java] JavaFXで表
久しぶりにJavaFXをいじる。前回から1ヶ月経ってしまった。
JavaFX 2で始めるGUI開発 第5回 リスト、コンボボックス、テーブルを読んだ。テーブルが気になるので試してみた。
できあがり

名前と値を表示するだけ。値の方は編集可能。
表はデフォルトで縞々になるみたい。行や列が無い部分にもセルが補われて表示されている。
以下ソースコード。
行に表示するクラス
SwingのJTableとは違い行ベースの表を簡単に作れるみたい。次のようなRowクラスを作った。
package table;
public class Row {
private final String name;
private int value;
public Row(String n, int v) {
name = n;
value = v;
}
public String getName() { return name; }
public int getValue() { return value; }
public void setValue(int value) { this.value = value; }
}
- nameは変更不可で、valueは変更可能にしている。
コントローラクラス
package table;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.converter.IntegerStringConverter;
public class TableController implements Initializable {
@FXML
private TableView<Row> table;
@FXML
private TableColumn<Row, String> nameColumn;
@FXML
private TableColumn<Row, Integer> valueColumn;
@Override
public void initialize(URL url, ResourceBundle rb) {
nameColumn.setCellValueFactory(
new PropertyValueFactory<Row, String>("name"));
valueColumn.setCellValueFactory(
new PropertyValueFactory<Row, Integer>("value"));
valueColumn.setCellFactory(
TextFieldTableCell.<Row, Integer>forTableColumn(
new IntegerStringConverter()));
}
public void setRowList(ObservableList<Row> rowList) {
table.setItems(rowList);
}
@FXML
public void handleValueCommeted(CellEditEvent<Row, Integer> event) {
event.getRowValue().setValue(event.getNewValue());
}
}
- 表はTableView、列はTableColumnクラスで作れる。これらはFXMLの方で関連付ける。Rowクラスとの関連付けは型パラメータで行っている。
- initialize()にて、Rowのメソッドと列を関連付けている。文字列ベース。表示用にはcellValueFactory、編集用にはcellFactoryを設定するという理解でよい?cellValueFactoryにはPropertyValueFactoryクラス、cellFactoryにはTextFieldTableCellが生成するクラス使える。まだよく分かっていないな。
- 表に表示するRowオブジェクトをsetRowList()で設定するようにした。もっとスマートに設定したいけれど。
- handleValueCommited()は、値列の編集が完了したときに呼ばれる(ようにFXMLを書く)。編集結果を使ってRow#setValue()を呼び出している。
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="200.0" prefWidth="300.0"
xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/2.2"
fx:controller="table.TableController">
<children>
<ScrollPane fitToHeight="true" fitToWidth="true"
AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0"
AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0">
<content>
<TableView fx:id="table" editable="true" >
<columns>
<TableColumn minWidth="25" prefWidth="75"
text="名前" fx:id="nameColumn" />
<TableColumn minWidth="25" prefWidth="75"
text="値" fx:id="valueColumn"
editable="true" onEditCommit="#handleValueCommeted" />
</columns>
</TableView>
</content>
</ScrollPane>
</children>
</AnchorPane>
- 表の外側にScrollPaneを置いてみた。
- TableViewの中にTableColumnを置いている。
- 列のタイトルを設定している。
- 値列だけ編集可能にしている。
メインクラス
package table;
import java.io.IOException;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Table extends Application {
private ObservableList<Row> rowList;
@Override
public void init() {
rowList = FXCollections.observableArrayList(
new Row("壱", 1),
new Row("弐", 2),
new Row("参", 3));
}
@Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader loader =
new FXMLLoader(getClass().getResource("Table.fxml"));
loader.load();
TableController controller = loader.getController();
controller.setRowList(rowList);
Parent root = loader.getRoot();
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Table");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
- init()をオーバーライドし、そこでRowオブジェクトを生成してみた。TableViewに登録するにはObservableListというListを使う必要があって、FXCollectionsクラスを使うと簡単に生成できる。
- コントローラにRowオブジェクトを渡すため、FXMLLoaderインスタンスを明示的に生成している。FXMLLoader#getController()を使うとコントローラオブジェクトを取得できる。ジェネリックメソッドになっていてキャスト不要。
[ツッコミを入れる]