JavaFXで、ViewをFXMLファイルで定義したときの、Controllerの設定についてみていきます。
まず、以下のようなControllerを考えます。
public class SimpleViewController { @FXML private Parent root; public Parent getView() { return root; } }
とりあえず、ルートのコントロールのみを取得するだけにしています。
このControllerをFXMLファイルで定義したViewに設定するには、FXMLファイルにfx:controller属性で指定します。
<StackPane xmlns:fx="http://javafx.com/fxml" fx:controller="SimpleViewController" fx:id="root"> <Label text="Hello, world!"/> </StackPane>
あとは、javafx.fxml.FXMLLoaderでFXMLファイルをロードした後、getControllerメソッドからfx:controller属性で指定したControllerクラスのインスタンスを取得します。
FXMLLoader loader = new FXMLLoader(simpleViewLocation); loader.load(); SimpleViewController controller = (SimpleViewController)loader.getController();
上記では、FXMLファイルにControllerクラスを直接指定していますので、ViewがControllerに依存している形になっています。そこで、ViewがControllerに依存しないように、FXMLファイルに直接指定せずにControllerを設定してみたいと思います。
まず、FXMLファイルには次のようにfx:controller属性を指定しないようにします。
<StackPane xmlns:fx="http://javafx.com/fxml" fx:id="root"> <Label text="Hello, world!"/> </StackPane>
あとは、javafx.fxml.FXMLLoaderでFXMLファイルをロードする前に、setControllerメソッドでControllerクラスのインスタンスを設定します。
SimpleViewController controller = new SimpleViewController(); FXMLLoader loader = new FXMLLoader(simpleViewLocation); loader.setController(controller); loader.load();
この場合、FXMLファイルに直接fx:controller属性を指定しませんので、ViewがControllerに依存せずに、Controllerを設定できます。また、Controllerのインスタンスを指定しますので、他の依存するオブジェクトをControllerに注入したい場合にも利用できます。
次に、ControllerクラスをFXMLファイルで定義しているルート要素のコントロールとして定義する場合についてみていきます。
まず、FXMLファイルでViewを定義します。このとき、ルート要素はfx:rootとして定義します。
<fx:root xmlns:fx="http://javafx.com/fxml" type="StackPane"> <Label text="Hello, world!"/> </fx:root>
type属性に、ルートとなるコントロールの型を指定します。
次に、type属性で指定した型を継承して、Controllerクラスを定義します。
public class SimpleControl extends StackPane { private static final URL VIEW_LOCATION = SimpleControl.class.getResource("SimpleControl.fxml"); public SimpleControl() { initializeComponent(); } protected void initializeComponent() { FXMLLoader loader = new FXMLLoader(VIEW_LOCATION); loader.setController(this); loader.setRoot(this); try { loader.load(); } catch (IOException e) { throw new RuntimeException(e); } } }
javafx.fxml.FXMLLoaderでFXMLファイルをロードする前に、setControllerメソッドとsetRootメソッドにControllerクラスのインスタンスを設定します。
上記で定義したControllerをシーンに設定してみます。
Scene scene = SceneBuilder.create() .root(new SimpleControl()) .build();
上記のように設定した場合は、.NETでいうコードビハインドのような感じになります。
FXMLファイルでViewを定義した場合、Controllerの設定には、基本的に上記の2番目か3番目の方法で行うことになると思います。3番目の方法の場合は、Controllerというよりは、カスタムコントロールという位置づけになり、他のFXMLファイルにそのまま要素として指定することができますので、.NETで開発したことがある人には、馴染みやすいかもしれません。
FXMLファイルでViewを定義した場合は、javafx.fxml.FXMLLoaderクラスを使ってFXMLファイルを読み込むのですが、同じような記述を毎回行うことになりますので、次回は、FXMLファイルを読み込んでControllerを取得するユーティリティクラスを作成してみたいと思います。