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()を使うとコントローラオブジェクトを取得できる。ジェネリックメソッドになっていてキャスト不要。
2014年02月08日(土) [長年日記]
- ソチオリンピックが開幕した。
- 関東地方は雪。20年ぶりの大雪とのこと。
■ [java] JavaFXのバインドを試す
JavaFX 2で始めるGUI開発 第6回 プロパティとバインドを読んだ。バインドは便利そう。
この前作った掛算画面がイベントハンドラではなくバインドを使っても実現できそうなので試してみた。コントローラクラスだけを書き換えて次のようにした。
package hello; import java.net.URL; import java.util.ResourceBundle; import javafx.beans.binding.Bindings; import javafx.beans.binding.DoubleBinding; import javafx.beans.value.ObservableStringValue; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.input.KeyEvent; public class HelloController implements Initializable { @FXML private TextField leftField; @FXML private TextField rightField; @FXML private Label resultLabel; @Override public void initialize(URL url, ResourceBundle rb) { resultLabel.textProperty().bind(Bindings.multiply( new StringDoubleBinding(leftField.textProperty()), new StringDoubleBinding(rightField.textProperty())).asString()); } @FXML public void handleKey(KeyEvent event) {} static class StringDoubleBinding extends DoubleBinding { private final ObservableStringValue source; public StringDoubleBinding(ObservableStringValue s) { super.bind(s); source = s; } @Override protected double computeValue() { try { return Double.parseDouble(source.getValue()); } catch (NumberFormatException ex) { return 0; } } } }
- initialize()にてresultLabelにleftFieldとrightFieldの積をバインドしている。
- 掛算をBindings.multiply()に任せたのだけれど、そうするにはStringPropertyをObservableNumberValueに、NumberBindingをObservableValue<? extends String>にそれぞれ変換する必要がある。後者はNumberBinding#asString()でできるけど、前者の変換方法が分からなかった。仕方ないのでDoubleBindingを拡張したStringDoubleBindingクラスを自前で用意した。
- handleKey()は不要だけれど、以前のFXMLを使いまわしているので残している。
以前とは違い、テキストフィールドの値が数値でないときに結果が0と表示されてしまう。
2014年02月16日(日) [長年日記]
- 二回続けて週末に大雪。今回の方が積もった。雪かきをして腰を痛めた。
- ソチオリンピック開催中。これまで角野、上村、フィギュアスケート団体、葛西、加藤、長島、小平、平野、平岡、高梨、伊藤、渡部、岡田、羽生、町田、高橋といった方々が入賞した。
■ [java] 「JavaFX 2ではじめる、GUI開発」の目次
連載記事のJavaFX 2で始めるGUI開発を全部読んだ。どんどん斜め読みになったけれど。どういうわけか個々の記事への目次がなくて不便なので、現時点での記事一覧をここにメモ。
- 第1回 JavaFX 2とは (2012/08/06)
- 第2回 シーングラフとFXML (2012/09/03)
- 第3回 コントロール その1 (2012/10/01)
- 第4回 コントロール その2 (2012/11/05)
- 第5回 リスト、コンボボックス、テーブル (2012/12/03)
- 第6回 プロパティとバインド (2013/01/07)
- 第7回 レイアウト その1 (2013/02/04)
- 第8回 レイアウト その2 (2013/03/08)
- 第9回 CSSによるスタイリング (2013/04/05)
- 第10回 組み込みブラウザとチャート (2013/05/10)
- 第11回 エフェクトとトランスフォーム (2013/06/07)
- 第12回 トランジションで簡単アニメーション (2013/07/05)
- 第13回 タイムラインを使ったアニメーション (2013/08/02)
- 第14回 非同期処理 (2013/09/06)
- 第15回 基本的なシェイプ (2013/10/04)
- 第16回 パスとシェイプに関するトランジション (2013/10/18)
- 第17回 キャンバス (2013/11/01)
- 第18回 イメージのピクセル操作 (2013/11/15)
- 第19回 タッチインタフェース (2013/12/06)
- 第20回 ジェスチャー (2013/12/20)
- 第21回 コピー&ペースト (2014/01/10)
- 第22回 ドラッグ&ドロップ (2014/01/24)
- 第23回 デプロイメント (2014/02/21)
● FX初心者 [まさしく、これがやりたくて探し回っていました。 もっと簡単に型変換できるAPIがあると思っていたのですが、見つからず..]