[Groovy]JavaFXで外部ツールを起動する

# 概要

[お気に入りのWebとエディタとかに移動できるGUIを作ってみた（ちょっと暇つぶし）](http://qiita.com/Librorum_/items/ef28d5556a6ab5fd7ea0)という投稿を見て、なるほどやっぱりGUI弄るとなるとC#はスッキリしてるなーと思い、そういえばGroovyでGUIツール書いたことないなと思い立ってJavaFXで同じような事をしてみました。
GroovyFXを試そうと思ったのですが、何故かGrabでライブラリを見つけられなかったのでJavaFXをそのまま利用しています。

Java8上で動いているGroovy 2.4.7で確認しています。
基本的に以下のコードをそのまま`sample.groovy`というようなファイルに保存して、`groovy sample.groovy`と実行するだけでOKです。

# コード

以下が全体のコードです。
元記事ではUnityを起動しているようですが、自分の環境にはインストールしていないので、とりあえずOS標準のエディタでhostsファイルを開くようにしてみました。（on Linux）

```groovy
import javafx.application.Application
import javafx.event.EventHandler
import javafx.scene.Scene
import javafx.scene.control.Button
import javafx.stage.Stage
import javafx.scene.layout.GridPane
import java.awt.Desktop
import javafx.geometry.Insets
import javafx.scene.control.TextField
import javafx.scene.control.Label
import javafx.scene.layout.ColumnConstraints

 
public class App extends Application {
    public void start(Stage primaryStage) {
        Button button = new Button()
        button.text = "Open Twitter with default browser"
        button.onAction = { 
            Thread.start{
                String url = "https://twitter.com/"
                Desktop.getDesktop().browse(new URI(url))
            }   
        } as EventHandler

        Button button2 = new Button()
        button2.text = "Show hosts file"
        button2.onAction = { 
            Thread.start {
                File f = new File ("/etc/hosts")
                Desktop.getDesktop().open(f)
            }   
        } as EventHandler

        // 追加。テキストフィールドに入力した値を実行（エディタとか）
        // Windowsならxxx.exeみたいな感じ。Linux（Ubuntu）ならgeditとか行ける）
        // セキュリティ的に考慮すべきこと多数！
        TextField textField = new TextField()
        Label label = new Label("URL:")
        Button button3 = new Button()
        button3.text = "execute programm"
        button3.onAction = {
            Thread.start {
                String str = textField.getText()
                Process p = str.execute()
            }
        } as EventHandler


        GridPane pane = new GridPane()
        pane.setPadding(new Insets(10))
        pane.setHgap(10)
        pane.setVgap(10)

        pane.add(button, 0, 0)
        pane.add(button2, 0, 1)
        pane.addRow(3, button3, textField)


        Scene scene = new Scene(pane, 300, 250)
        primaryStage.setTitle("Hello World!")
        primaryStage.setScene(scene)
        primaryStage.show()
    }   

    static main(args) {
        launch(App.class, args)
    }   
}
```

## メモ
基本的にはJavaのコードと同様ですが、Groovyの機能を活かすことによって、buttonに動作を割り当てる`setOnAction()`がかなり簡略化できています。
Javaで普通に書くと

```java
btn.setOnAction(new EventHandler<ActionEvent>() { 
    public void handle(ActionEvent event) { 
        System.out.println("Hello World"); 
    }
}); 
```
というような記述になる所が、

```groovy

btn.onAction = {
    println "Hello World"
}
```
とかなりスッキリ表現することが出来ます。（Java8のラムダ式とか使えばJavaでももっとスッキリ書けるはず？）
（全体コードでは、分かりやすいように意図的に`as EventListener`と記述していますが、このように別にasで型を強制変換する必要はありません。）

（追記）
コメントでJava8バージョンを教えて頂きました。
ラムダ式を使うとやはりかなり簡潔になります。
上記の部分であれば、

```java
btn.setOnAction(event -> {
    println "HelloWorld"
});
```
というように表現できるようです。Java8でもかなり簡潔になりますね！

# まとめ
Java1.5時代のSwingアプリしかまともに作ったことがないので、2017年のマシンパワーを利用すると意外にさくっと起動するな、という感じで驚きました。
C#だと`Process.Start()`で別スレッドで外部ツールを起動できるようですが、JavaFXのonActionだと手動で別スレッドを起動しないといけないっぽくてそこが少し面倒臭いな、と思いました。
そのための専用メソッドが有ったりもっとスマートな表現方法があったりするのか、時間があるときに色々調べてみたいと思います。