LoginSignup
1
3

More than 5 years have passed since last update.

Kotlin+JavaFXで画面遷移

Last updated at Posted at 2017-06-24

はじめに

JavaFXの画面遷移がKotlinで綺麗に書けたので、投稿してみます。

環境

Kotlin 1.1.2
JDK 1.8.0_131

作るもの

ボタンがある2つの画面を用意して、ボタンを押すともう片方の画面に遷移するプログラムを作ります。
画面遷移.png

条件

fxmlファイル名と対応するコントローラーのKotlinのファイル名が同じで、同一パッケージ内に入っていることが前提です。異なるファイル名やパッケージでやりたい場合には、MainAppクラスのreplacePaneを書き換えて下さい。

Application

MainApp.kt
class MainApp : Application() {
    private lateinit var stage: Stage   // replacePaneで参照する

    override fun start(primaryStage: Stage) {
        stage = primaryStage
        replacePane(Page1())
        stage.show()
    }

    fun replacePane(controller: Any) {
        val classPath = controller.javaClass.name
        val className = controller.javaClass.simpleName
        val loader = FXMLLoader(Class.forName(classPath).getResource("$className.fxml"))
                .apply { setController(controller) }
        val parent = loader.load<Parent>()
        stage.title = className
        stage.scene = Scene(parent)

        // スマートキャストでtransitionをreplacePaneで初期化できる
        if (controller is TransitionPane) {
            controller.transition = this::replacePane   // 関数参照
        }
    }
}

MainAppのstageのsceneを入れ替えることで画面遷移を実現しています。画面遷移のために呼び出されるメソッドは、replacePaneで遷移先のコントローラーを引数に取ります。

MainApp.kt
interface TransitionPane {
    var transition: ((Any) -> Unit)
}

TransitionPaneは、関数リテラルのプロパティであるtransitionを持つインターフェースです。このインターフェースを、画面遷移させたい(遷移元)コントローラーに実装してあげることで、transitionからreplacePaneを呼べるようにします。replacePaneの中でコントローラーのtransitionがreplacePaneで初期化されています。

MainApp.kt
fun main(args: Array<String>) {
    Application.launch(MainApp::class.java, *args)
}

ちなみに、プログラムの起動はこんな感じで行います。

Controller

Page1.kt
class Page1 : Initializable, TransitionPane {
    override lateinit var transition: ((Any) -> Unit)
    @FXML lateinit var toPage2: Button

    override fun initialize(location: URL?, resources: ResourceBundle?) {
        toPage2.setOnAction { transition(Page2("Kotlinかわいいよ")) }
    }
}

1つ目の画面のコントローラーです。ポイントは、オーバーライドしたtransitionにlateinitをつけることで、MainAppのreplacePaneから初期化できるようにしている所です。

Page2.kt
class Page2(val labelText: String) : Initializable, TransitionPane {
    override lateinit var transition: ((Any) -> Unit)
    @FXML lateinit var toPage1: Button
    @FXML lateinit var label: Label

    override fun initialize(location: URL?, resources: ResourceBundle?) {
        toPage1.setOnAction { transition(Page1()) }
        label.text = labelText
    }
}

2つめの画面のコントローラーも同じような感じです。fxmlのfx:controllerでコントローラーを指定するのではなく、FXMLLoaderのsetControllerで指定するようにすることで、コントローラーのコンストラクタに引数を設定できるようになります。

FXML

fxmlはFlowPaneにボタンとかを置いただけです。

Page1.fxml
<FlowPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" >
   <children>
      <Button fx:id="toPage2" mnemonicParsing="false" text="Page2へ" />
   </children>
</FlowPane>
Page2.fxml
<FlowPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Button fx:id="toPage1" mnemonicParsing="false" text="Page1へ" />
      <Label fx:id="label" text="Label">
         <FlowPane.margin>
            <Insets left="10.0" />
         </FlowPane.margin></Label>
   </children>
</FlowPane>

おわりに

画面遷移がコンパクトに分かりやすく書けたかと思います。
それにしてもKotlinは書いていて気持ちがいいですね!Kotlinかわいいよ、Kotlin。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3