S-JIS[2012-04-07] 変更履歴

FXML Controller

JavaFXFXMLのコントローラーのメモ。

 

概要

FXMLドキュメントをJavaのクラスと結びつけて、イベントを処理したり値を取得したりすることが出来る。
このクラスをコントローラーと呼ぶ。

FXMLのルート要素のfx:controller属性でコントローラークラスを指定する。
コントローラークラスには、実装すべきインターフェースや親クラスは特に無い。
実行時(FXMLLoader#load()を呼び出した時)に自動的にこのクラスのインスタンスが作られる。
(クラスが見つからなければ、ClassNotFoundExceptionを原因とする例外が発生する)


イベントを捕捉する例

ボタン押下のイベントを捕捉する例。

D:/javafx/sample/button1.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<Pane fx:controller="example.Button1Controller" prefWidth="256" prefHeight="212" xmlns:fx="http://javafx.com/fxml">
  <children>
    <Button text="Click Me!" onAction="#handleButtonAction"/>
  </children>
</Pane>

src/example/Button1Controller.java

package example;
import javafx.event.ActionEvent;
public class Button1Controller {

	public void handleButtonAction(ActionEvent event) {
		System.out.println("Controller: button clicked");
	}
}

ボタンタグのonAction属性でメソッド名を指定する。
ボタンが押されると、コントローラークラスのそのメソッドが呼ばれる。

コントローラークラスには特に親クラスは無く、したがってメソッドも何かをオーバーライドしたりはしない。


値にアクセスする例

FXMLでTextField等の入力エリアを配置し、コントローラークラスでその値を読み書きすることが出来る。

D:/javafx/sample/button2.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox fx:controller="example.Button2Controller" prefWidth="256" prefHeight="212" xmlns:fx="http://javafx.com/fxml">
  <children>
    <TextField fx:id="text1" />
    <Button text="Click Me!" onAction="#handleButtonAction"/>
    <Label fx:id="label1" />
  </children>
</VBox>

src/example/Button2Controller.java

package example;
import javafx.event.ActionEvent;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
public class Button2Controller {

	public TextField text1;
	public Label label1;

	public void handleButtonAction(ActionEvent event) {
		String s = text1.getText();
		label1.setText(s);
	}
}

FXMLファイルのシーン(TextFieldやLabel)にfx:id属性で名前を付ける。
そして、コントローラークラスのフィールドとして、同名のpublicフィールドを用意する。
すると、コントローラークラス内のフィールドと表示されているコンポーネントの値が連動される。


初期値の設定

コントローラークラスの初期化用のメソッドを用意することが出来る。
インスタンスが作られるとこのメソッドが呼ばれる。

コントローラークラスにInitializableインターフェースを実装し、initialize()メソッドを書く。

import java.net.URL;
import java.util.ResourceBundle;

import javafx.fxml.Initializable;
public class Button2Controller implements Initializable {
〜
	@Override
	public void initialize(URL url, ResourceBundle resourcebundle) {
		text1.setText("初期値");
		label1.setText("ここにコピーされる");
	}
〜
}

@FXMLアノテーション

上記の例ではコントローラー内のフィールドやイベント処理用のメソッドをpublicにしていたが、public以外にしたい場合は@FXMLアノテーションを付ける。

ただし、リフレクションsetAccessible(true)が呼ばれることになるので、SecurityManagerの設定によっては使えない。

import javafx.fxml.FXML;
public class Button2Controller {

	@FXML private TextField text1;
	@FXML private Label label1;

	@FXML protected void handleButtonAction(ActionEvent event) {
		〜
	}
}

publicでないフィールドに@FXMLが付いていない場合は初期化時に例外(IllegalAccessException)が発生するが、
イベント用のメソッドだと、そのメソッドが呼び出される時に初めてチェックされるので、テスト漏れなど起こさぬよう注意が必要。


コントローラーインスタンスの取得

コントローラーのインスタンスはロード時に自動的に作られる。
FXMLLoaderインスタンスを使ってロードすれば、コントローラーインスタンスを取得できる。

	URL file = new File("〜").toURI().toURL();
	FXMLLoader loader = new FXMLLoader();
	Parent root = (Parent) loader.load(file.openStream());

	MyConroller controller = (MyController) loader.getController(); //古いJavaFX2ではキャストが必要

FXML目次へ戻る / JavaFXへ戻る / Javaへ戻る / 技術メモへ戻る
メールの送信先:ひしだま