Kotlinで超簡単にデスクトップアプリを作る

KotlinでもVBやVCのように簡単にデスクトップアプリを作ることが出来ます。
要点は以下のとおりです。

- IntelliJにTornadoFXプラグインをインストールする
- IntelliJからSceneBuilder(GUI作成ツール)を呼び出せるようにする
- Viewクラス（Formに相当）のrootプロパティにSceneBuilderで作成したFXMLファイルを関連付ける
- 使用したいウィジェット（Controlに相当）のfxidをプログラム中の変数と関連付ける

これから具体的な方法を説明します。
##必要なもの
IntelliJ (Commutity EditionでOK)
SceneBuilder

##準備
###SceneBuilder
http://gluonhq.com/products/scene-builder/ から
使用しているOS、JavaのバージョンにあったSceneBuilderをダウンロードしてインストールします。
※後で使うのでSceneBuilderファイルのインストール先を控えておきましょう。

###IntelliJ
**次のプラグインをインストールします**
　　TornadoFX (JavaFX、Kotlinは既に入っています）

**設定**
**File → Settings → Languages & Frameworks → JavaFX**
　　"Path to SceneBuilder" を設定します
　　 ※先ほど控えておいたSceneBuilderの保存先を設定します。

##プロジェクトの作成
今回はすべて初期値のままのプロジェクト名:untitledで作成します。
**TornadoFX → tornadofx-gradle-project**を選択して
そのまま初期値でプロジェクトを作成します。

  　 ※2020年4月20日現在
  　　このままではgradleのバージョンが古いのでビルドできません。
  　　untitled/gradle/wrapper/gradle-wrapper.propertiesファイルを開いて
  　　1行目のgradle-4.4-bin.zipのバージョンを変更します。
  　　この原稿を書いている時点で最新版は6.3ですが、エラーが出るので5.6.4に変更しました。


  　　TornadoFX frameworkを認識させます。
  　　<img src="https://qiita-image-store.s3.amazonaws.com/0/42061/daf22101-0e68-8da3-4200-7abc68b7470b.png" width=50%>

MainVew.ktやMyApp.ktファイルを開いて左側にTornadoFXのアイコンが表示されていればOKです。
アイコンをマウスクリックして実行してみましょう。
<img src="https://qiita-image-store.s3.amazonaws.com/0/42061/0135d10e-5d85-0e70-0155-d2b18218cb9c.png" width=40%>
うまく実行できない場合は**Run → Edit Configurations...**を開いて**App Class**や**View Class**が正しく設定されているか確認してください。

##FXMLファイルの作成
ここからが本番です。

src/mainフォルダの下にresourcesフォルダ、fxmlフォルダを作成し、その中にfxmlファイルを作ります。（マウスの右クリックで作成できます)
<img src="https://qiita-image-store.s3.amazonaws.com/0/42061/31ab825f-6432-4272-f435-551f0f777d7b.png" width=60%>
自動作成されるfxmlファイルにはfx:controllerの指定がありますが、これはいらないので行を削除するか、一旦全部削除してSceneBuilderで作りなおしてください。
SceneBuilderはプロジェクト画面でfxmlファイルをダブルクリックするか、右クリックしてコンテキストメニューの下の方にある**Open In SceneBuilder**で起動できます。

SceneBuilderの使い方はここでは割愛します。

次に進むためfxmlコードを全部削除して次のコードでfxmlファイルを作成してください。

```main_view.fxml
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="243.0" prefWidth="382.0" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Button fx:id="sampleButton" layoutX="257.0" layoutY="128.0" mnemonicParsing="false" text="Button" />
      <TextArea fx:id="sampleTextArea" layoutX="21.0" layoutY="19.0" prefHeight="200.0" prefWidth="200.0" />
   </children>
</AnchorPane>

```
SceneBuilderで見ると次のようになります。
<img src="https://qiita-image-store.s3.amazonaws.com/0/42061/5036ac21-2d85-bc2a-ab72-4254862b7d16.png" width=80%>
**AnchorPane**に**Button**と**TextArea**を貼り付けただけのものですが、それぞれに"sampleButton","sampleTextArea"という**fxid**を設定しています。


##MainView.ktの書き換え
自動生成されるMainviewクラスは下のようになっています。

```Kotlin
class MainView : View("Hello TornadoFX") {
    override val root = hbox {
        label(title) {
            addClass(Styles.heading)
        }
    }
}
```
これを次のように書き換えます。

```Kotlin
class MainView : View("Hello TornadoFX") {
    override val root: AnchorPane by fxml("/fxml/main_view.fxml")
    private val button: Button by fxid("sampleButton")
    private val textArea: TextArea by fxid("sampleTextArea")

    init {
        button.action {
            textArea.text = "Hello TornadoFX by FXML"
        }
    }
}
```
見てわかるとおり、Viewクラスの**root**プロパティを**by fxml**を使ってFXMLファイルに関連付けするだけです。
この例ではmain_view.fxmlファイルのトップレベルのコンテナAnchorPaneに合わせてrootプロパティもAnchorPaneで宣言しています。
あとは使用したいウィジェットを**by fxid**を使ってを使ってプライベート変数に関連付けします。
イベントハンドラはinit部で定義します。

上の例の**button.action**メソッドの引数は**op:() -> Unit**型のラムダ式なので迷うことはありませんが、マウスクリック時の座標を取りたい時などは
**File → Settings → Editor → Appearance　**
"Show parameter name hints" をチェックしておくと引数のヒントが表示されるので便利です。