JavaFX + Kotlinでアプリを作っている最中なのですが、ハマったのでメモ。
JavaFXのSceneBuilderでズバッと部品を置いていくとFXMLができてくれるのですが、あまりにも長くなると読みにくいので、パーツ化していこうと思ってメニューをfx:includeで切り出しました。
最初のコードはこんな感じ。見通しをよくするために属性を削ってますので注意。
main.fxml(fx:controllerでcom.example.Controllerを指定)
<?xml version="1.0" encoding="UTF-8"?>
<VBox xmlns:fx="http://javafx.com/fxml"
fx:controller="com.example.Controller">
<children>
<fx:include source="menu_bar.fxml"/>
<TableView fx:id="table">
<columns>
<TableColumn text="No." fx:id="idColumn" />
<TableColumn text="名前" fx:id="nameColumn" />
<TableColumn text="E-mail" fx:id="emailColumn" />
</columns>
</TableView>
<!-- 略 -->
</children>
</VBox>
menu_bar.fxml(同じく、fx:controllerでcom.example.Controllerを指定)
<?xml version="1.0" encoding="UTF-8"?>
<MenuBar
xmlns:fx="http://javafx.com/fxml"
fx:controller="com.example.Controller">
<!-- 略 -->
</MenuBar>
TableViewを使っているので、テーブルを表示しようとController#initializeメソッド内でテーブルを初期化しようとしたところ、ぬるぽで落ちました。
私は単純に、includeはFXMLの中にFXMLを埋め込むだけのものだろうと思っていたのですが、どうやら違うようです。
どうもfxmlファイル毎に初期化処理が行われるようで、2つのfxmlファイルが1つのコントローラーを指定していたらinitializeメソッドが正常に機能しないようです。
ここでは、main.fxmlとmenu_bar.fxmlで別々にControllerを定義する必要があります。
menu_bar.fxml(fx:controllerでcom.example.MenuControllerを指定)
<?xml version="1.0" encoding="UTF-8"?>
<MenuBar
xmlns:fx="http://javafx.com/fxml"
fx:controller="com.example.MenuController">
<!-- 略 -->
</MenuBar>
そして、メニュー用のコントローラーを作ればOK。
1つのコントローラーではダメなんですねぇ…。
