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()を使うとコントローラオブジェクトを取得できる。ジェネリックメソッドになっていてキャスト不要。