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つのコントローラーではダメなんですねぇ…。