Kotlin
tornadoFX

Kotlin ~TornadoFXを使ったデスクトップアプリ開発~

初めに

どこを探してもTornadoFXについて書いてくれている記事がなかったので、最初簡単なアプリを作るのさえかなり苦労しました。この記事は、TornadoFXを始めようと思ったがどうすればいいのかわからない、そもそもTornadoFXって何?といった方向けの導入を目標に書いています。僕みたいに初めてのデスクトップアプリ開発をいきなりTornadoFXから始めるような人でない限り、build.gradleの欄まで読み終えたら公式ガイドを参考にバリバリ作れるようになると思います。
先に断っておきますが、本記事はAndroidアプリ開発とは全く関係ない内容ですのでご注意ください。
また筆者自身がTornadoFXどころかKotlin初心者なので間違ったことを書いている場合もあります。その際は指摘していただけると幸いです。

TornadoFXとは?

TornadoFXとは、KotlinのGUI周りを補完するための強力なサードパーティ製ライブラリです。JavaFXを拡張したライブラリのため名前にFXを冠しています。KotlinはJavaとの相互100%互換を謳っています。それはJavaの力を借りないと書けないこともある、ということです。それの一つがGUIです。2017/8月現在Kotlinのバージョンは1.1.4ですが、Kotlin専用の標準GUIライブラリは実装されていません。そのためデスクトップアプリを作るとなるとJavaFX(AWT,Swing)などを用いて書くことになります。せっかくKotlinを使っているのだからKotlinだけで作ってみたいと思いませんか?そんな方のためにお勧めするのがこのTornadoFXなのです!

TornadoFXのメリット・デメリット

TornadoFXはJavaFXをKotlinライクで書けるようにするためのライブラリです。Kotlin自体が後発言語であることもあってスマートに書くことができます。開発陣も非常に熱心なためユーザーからの提案を実装したり、またIntelliJ IDEAのプラグインが開発されており、実際に使うことができます。Apache License 2.0に基づくオープンソースなので全ソースコードを見ることができます。(https://github.com/edvin/tornadofx) 全編英語ながらガイドブックも充実しており、Youtubeには実際にアプリを作るチュートリアル動画も投稿されています。
しかし、先ほど「JavaFXをKotlin ライク で書ける」といった通り、現状まだJavaの力を借りないといけないところが多々あります。例えば、色を指定するためにはjavafx.scene.paint.Colorをインポートしなければなりません。また、TornadoFXを用いて開発をするにはgradleやmavenなどのビルドツールを使用しなくてはなりません。その分手間もかかりますし、gradleなどを使うための学習コストも増えます。実用性を重視するならばJavaFXを用いるべきでしょう。その方がネットに情報も多く転がってますし、簡単なテストならコマンドプロントで実行できます。

前準備

では実際にTornadoFXを使ってアプリを作る準備をしましょう。IntelliJ IDEAを使っている方は、先ほども言いましたがすでにプラグインが公開されているのでダウンロードしましょう!
以降はIDEに左右されないよう、または僕みたいにそもそもIDEすら持ってない人のための説明になります。

筆者の環境

  • Windows 10 Home
  • Intel Core i7-5600U
  • RAM 8GB
  • 64bit x64

windowsのためコマンドプロントを使用した開発をします。macの方は適宜読み替えてください。

gradleのインストール

gradleの初歩についてはこちらの記事が詳しいです。僕もかなり参考にしました。
Gradle初心者によるGradle事始め
今回はCドライブ直下にgradleというフォルダを作り、その中にgradle本体のファイル群を保存しました。

ディレクトリ構成

gradle
├ gradle-3.2.1 //gradle本体
│
└ app //プロジェクト名なので自由に名前をつけてよい
  ├ build.gradle 
  └ src
    ├ main
    │ └ kotlin
    │   └ demo  //このフォルダにソースコードを保存。パッケージ名なので自由に名前をつけてよい
    └ test
      └ kotlin

実際にビルドするといろんなフォルダやファイルが作成されますが無視して大丈夫です。

実際に作る

MyApp.kt

JavaFXでコードを書く場合、必ず以下のようなエントリーポイントを作成します。

ApplicationLaunchSample.java
package launchcodeSample;

import javafx.application.Application;
import javafx.stage.Stage;

public class Launcher extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        ...
    }

}

javaFXでは、javafx.applicationクラスのApplicationを継承したクラスを作成し、そこからアプリが実行されます。実際に開発されたことのある方ならわかると思いますがmainメソッドは必要ありません。なぜ必要ないのかは以下の記事が解き明かしてくれます。
[JavaFX]JavaFXアプリケーションクラスにmainメソッドがなくてもよい訳

ではTornadoFXを用いた時のエントリーポイントを作成しましょう。

MyApp.kt
package demo

import tornadofx.App

class MyApp:App(MyView::class)

なんと実質3行で書き終わってしまいました!なぜstartメソッドを書く必要がないかというと、継承元のAppApplicationを継承しており、またstartメソッドをオーバーライドしてあるためです。そのためMyAppはすでにstartメソッドを所持しているのです。mainメソッドが必要ない理由はJavaFXの時と同じ理由です。MyViewはJavaFXにおけるStageと同等です。
ではレイアウトを構成しましょう。

MyView.kt
package demo

import tornadofx.*

class MyView : View(){
  override val root = Form()

  init{
    with(root){
      fieldset{
        field("Hello tornadofx!")
      }
    }
  }
}

ただHello tornadofx!を表示するだけの簡単なレイアウトです。MyView.ktを別ファイルとして作成していますが、MyApp.ktにまとめて書くこともできます。

MyApp.kt
package demo

import tornadofx.App
import tornadofx.*

class MyApp:App(MyView::class)

class MyView : View(){
  override val root = Form()

  init{
    with(root){
      fieldset{
        field("Hello tornadofx!")
      }
    }
  }
}

一つのファイルにまとまるので結構すっきりしますね!
rootはJavaFXから続投しているのでoverrideします。rootのプロパティに設定したForm()は、JavaFXのVBox()を継承したtornadoFXのプロパティです。tornadofx.Formsに定義されています。rootのプロパティを設定するには、kotlinのイニシャライザを使います。initブロック内に登場するfieldsetはFormクラスに属するプロパティです。

internal val fieldsets = HashSet<Fieldset>()

と定義されています。Fieldsetは、これもtornadofx.Formsに定義されたVBox()を継承したクラスです。

  fieldset{
    field("Hello tornadofx!")
  }

によってHello tornadofx!をセットしています。

build.gradle

ではいよいよ作成したコードを実行するためにbuild.gradleを書きましょう。

build.gradle
buildscript {
  ext.kotlin_version = '1.1.2'
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
  }
}

apply plugin: 'kotlin'
apply plugin: 'application'

compileKotlin{
  kotlinOptions.jvmTarget = "1.8"
}

repositories {
  mavenCentral()
}

dependencies {
  compile "no.tornado:tornadofx:1.7.10"
  compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

  testCompile 'junit:junit:4.11'
}

mainClassName = 'demo.MyApp'

僕自身がgradleに全く詳しくなく、実行できればいいやーな意識なので変なところがあるかもしれません。
注意すべきこととしては、TornadoFXがjava 8、kotlin 1.1.2以上を要求しているため、jvmTargetに1.8、kotlin_versionに1.1.2を指定することでしょう。JavaFXそのものがjava 8の機能なので当然ですね。また日々TornadoFXはバージョンアップしているので、dependencies内のtornadofxのバージョン指定は適切にしてやる必要があります。執筆時点でのバージョンは1.7.10です。
mainClassNameでApp()を継承したクラスをパッケージ名から書きます。つまりローンチャを指定してるわけです。ファイルを作成したら先ほどディレクトリ構造に書いたようにsrcと同じ階層に保存します。

実行する

それではいよいよビルドしましょう!コマンドプロントを起動し、build.gradleのある階層まで移動します。
gradle buildを打ちます。途中経過はぶっちゃけどうでもよく、以下のように最後にBUILD SUCCESSFULと表示されれば成功です。ビルドに失敗したらエラー内容を見ながらソースコードを見直してください。TornadoFXを使ったアプリを初めてビルドする場合、最初に一生懸命ライブラリをダウンロードしてる様子が見れます。その後は比比較的早くビルドが終わります。
無題.png

ビルドが終わったのでいよいよ実行です。緊張の一瞬。。。
gradle runを打ちます。
hellotornadofx.png
成功しました!僕はこの画面を見た時に思わず拍手してしましました。なにせ初めて(まがいなりにも)デスクトップアプリを作ったのですから。
この画面が表示されている間は常にアプリ実行状態として扱われます。コンソールを見るとわかりますが>Building 83%>:runと表示されたままになっていると思います。アプリを閉じると最終的に以下の画像のようになります。
無題.png

後始末にタスクマネージャーを起動して裏でメモリを食ってるjava Platform Binaryを終了させておきましょう。心当たりがないのにファンがうるさい時は大体こいつのせいです。

終わりに

これでTornadoFXの導入部は終わりです。この記事で少しでも多くの人がTornadoFXの使い方を知っていただけたなら本望です。今後も少しずつTornadoFXの勉強を進めながら記事を書いていくと思います。ここからは実用的なアプリを作っていくことになりますが、すでにデスクトップアプリ開発をしたことがある方でしたらガイドを読んだ方が早いと思います。以下にリンクを貼っておきますので参考にしてください。

TornadoFXガイド

  • TornadoFX Wiki

https://github.com/edvin/tornadofx/wiki

  • TornadoFX guide

https://github.com/edvin/tornadofx-guide

続編を書きました

TornadoFXでデスクトップアプリ開発 ボタン編