Kotlin - TornadoFX 1

JavaFXをKotlinらしく使いましょうなライブラリ、フレームワーク。
ガイドの最初の方だけ見た。

楽に書けるなぁと思いつつ。

準備

Gradleを使っているので、dependenciesを追加すればすぐ使えるようになる。
IntelliJが自動生成してくれるbuild.gradleにTornadoFXを追加すると以下のような感じになる

buildscript {
    ext.kotlin_version = '1.2.30'

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

group 'com.github.dekirukigasuru'
version '1.0-SNAPSHOT'

apply plugin: 'kotlin'

repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    compile 'no.tornado:tornadofx:1.7.15'
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

基本コード

Appを継承したクラスを一つ、そのクラスにつけるViewを継承したクラス一つがそれぞれ必要。
Viewにおいてrootをオーバーライドして画面を構成していく。
その構成をJavaFXノードでしていくのだが、Kotlinぽく記述できる用意が色々されている感じ。

import javafx.application.Application
import tornadofx.*

class MyApp: App(MyView::class)

class MyView: View() {
    override val root = vbox {}
}

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

これでウインドウが表示される。 main()関数はなくても動くみたい。JavaFXがそもそもそうらしい。

Viewを切り替える

画面は切り替えられる。エフェクト付きで。
onDock()onUndock()を実装しておくと切り替え前後で呼び出される。

import javafx.application.Application
import tornadofx.*

class MyApp: App(MyView::class)

class MyView: View() {
    override val root = vbox {
        button("Go to MyView2") {
            action {
                replaceWith(MyView2::class)
            }
        }
    }

    override fun onDock() {
        super.onDock()
        println("docking view1")
    }

    override fun onUndock() {
        super.onUndock()
        println("undocking view1")
    }
}
class MyView2: View() {
    override val root = vbox {
        button("Go to MyView1") {
            action {
                replaceWith(MyView::class, ViewTransition.Slide(0.3.seconds, ViewTransition.Direction.LEFT))
            }
        }
    }

    override fun onDock() {
        super.onDock()
        println("docking view2")
    }

    override fun onUndock() {
        super.onUndock()
        println("undocking view2")
    }
}

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

MVCと非同期的な

表示とデータ処理は分けて実装できるようになっている。
例によって、時間のかかる処理をそのまま記述すると画面が固まる。
また、画面の更新はUIスレッドからしか行えない。
その辺簡単に書けるようになっている。

import javafx.application.Application
import tornadofx.*

class MyApp: App(MyView::class)

class MyView: View() {
    val controller: MyController by inject()

    override val root = vbox {
        label("Input")
        val inputField = textfield()
        button("Commit") {
            action {
                runAsync {
                    controller.writeToDb(inputField.text)
                } ui {
                    inputField.clear()
                }
            }
        }
    }
}

class MyController: Controller() {
    fun writeToDb(inputValue: String) {
        println("Writing $inputValue to database")
    }
}

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

ただし、難しいことする場合はRxを推奨している。
TornadoFX用のRxがある

その他

プロジェクトを簡単に作成できるIntelliJ用プラグインがある。


See also