JavaFXでHelloWorld

JavaFX の Hello World 作成方法メモ。
e(fx)clipse は使ってないけど、後々必要になるので入れておく。


#環境
##OS
Windows7 64bit

##Java
1.7.0_25

##IDE
Eclipse Juno

##Scene Builder
1.1

#準備
##Java FX のインストール
Java のバージョンが 1.7.0_6 以上なら標準でバンドルされてるので不要。

##Scene Builder のインストール
Oracle が提供してるフリーの Java FX 用 GUI デザインツール。
[ここ](http://www.oracle.com/technetwork/java/javafx/downloads/index.html)からダウンロードできる。

1.1 の Windows 版をダウンロードして、インストーラに従ってインストール。

##Eclipse プラグイン（e(fx)clipse）のインストール
__e(fx)clipse__ という Java FX 用のプラグインがあるので、マーケットプレースからインストール。

ちなみに、サポートしている Eclipse は、

> We support Eclipse Kepler (4.3.x) and Juno (4.2.x, 3.8.x). 

らしい（[e(fx)clipse - JavaFX Tooling and Runtime for Eclipse](http://www.eclipse.org/efxclipse/index.html)）。

###e(fx)clipse に Scene Builder の場所を設定する
「ウィンドウ」→「設定」→「JavaFX」と選択。
「SceneBuilder executable」に先ほどインストールした Scene Builder の実行ファイル（ `JavaFX Scene Builder 1.1.exe` ）のパスを入力する。

![Scene Builder の場所を設定](https://qiita-image-store.s3.amazonaws.com/0/28302/490821f4-42e4-fddc-764f-1c2cd4310550.jpeg)

#実装
##Java プロジェクトを作成する
普通に Java プロジェクトを作成する。

##Java FX の jar をクラスパスに追加する
**追記ここから**

Java8 からは、 JavaFX も標準で組み込まれるようになったので、以下の作業は不要になっています。

**追記ここまで**

そのままだと Java FX の jar がクラスパスに入ってないので実装できない。なので追加する。

Java FX の jar （ `%JDK のインストールフォルダ%\jre\lib\jfxrt.jar` ）をビルド・パスに追加する。

![JavaFXのjarを追加](https://qiita-image-store.s3.amazonaws.com/0/28302/b27a5d89-aecc-4a54-c9d8-9534defa0290.jpeg)

##Scene Builder で画面を作成する
Scene Builder を起動する。

左の __ライブラリパネル__ から「Label」を選択して、中央にドラッグ＆ドロップ。

![Labelの配置](https://qiita-image-store.s3.amazonaws.com/0/28302/665ec2ce-57ab-6dda-61d8-3a08b986506a.jpeg)

右の __インスペクタパネル__ の「プロパティ」でテキストとかフォントとかを適当にいじる。

![プロパティを変更する](https://qiita-image-store.s3.amazonaws.com/0/28302/dbd0cd61-ee18-69ee-1caf-170bc2f76058.jpeg)

Eclipse プロジェクトの `src` フォルダの直下に `hello.fxml` という名前で保存する。

![hello.fxmlの保存場所](https://qiita-image-store.s3.amazonaws.com/0/28302/6ded36c7-1fe4-8811-47b1-fe1a1c21804a.jpeg)

##Java の実装
```java:JavaFXMain.java
package fx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class JavaFXMain extends Application {
    
    public static void main(String[] args) {
        // JavaFX の実行
        Application.launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        // hello.fxml の読み込み
        Parent root = FXMLLoader.load(getClass().getResource("/hello.fxml"));
        
        // Scene の作成・登録
        Scene scene = new Scene(root);
        stage.setScene(scene);
        
        // 表示
        stage.show();
    }
}
```

##実行結果
![Hello World実行結果](https://qiita-image-store.s3.amazonaws.com/0/28302/dbf93c13-9a13-349f-f3b3-e12583587fbe.jpeg)


#イベント処理
ボタンのクリックイベントを取得する。

##fxml の編集
画面にボタンとラベルを配置する。

![ボタンとラベルを配置](https://qiita-image-store.s3.amazonaws.com/0/28302/864ea224-3692-ecec-4b39-24dc314ef9c6.jpeg)

左の __階層パネル__ で「AnchorPane」をクリックして、右のインスペクタパネルの「コード」の「コントローラ・クラス」に `fx.HelloController` と入力。

![コントローラクラス](https://qiita-image-store.s3.amazonaws.com/0/28302/6746cd76-42ec-9530-89cf-0d7eb059040a.jpeg)

**追記ここから**

Scene Builder 2.0 では、コントローラクラスを指定するための項目は画面左下に移動されました。

![javafx.JPG](https://qiita-image-store.s3.amazonaws.com/0/28302/0d8af074-9b5e-8f26-1482-cd315d13b378.jpeg)

最初分からずに混乱した。。。

**追記ここまで**

ボタンとラベルをそれぞれクリックして、インスペクタパネルの「コード」の「fx:id」を以下のように入力する。

|コンポーネント|fx:idに指定する値|
|:-------------------|:---------------------|
|ボタン              |helloButton          |
|ラベル              |helloLabel            |

![ラベルのfx:idを指定したところ](https://qiita-image-store.s3.amazonaws.com/0/28302/f7b32e90-4605-207a-1503-9f6afd0b6b50.jpeg)

ボタンを選択して、インスペクタパネルの「コード」の「On Action」に `onHelloButtonClicked` と入力。

![ボタンにOnActionを指定](https://qiita-image-store.s3.amazonaws.com/0/28302/3c6d69d6-311f-d5ca-5d09-ff9b144ac078.jpeg)

##コントローラクラスの作成
「AnchorPane」で指定した `fx.HelloController` を実際に作成する。

```java:HelloController.java
package fx;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;

public class HelloController {
    
    @FXML private Button helloButton;
    @FXML private Label  helloLabel;
    
    private int cnt;
    
    @FXML
    public void onHelloButtonClicked(ActionEvent event) {
        this.helloLabel.setText("clicked! : " + cnt);
        cnt++;
    }
}
```

##実行結果
![実行結果](https://qiita-image-store.s3.amazonaws.com/0/28302/791e276b-48db-4878-68c9-7f9be722501e.jpeg)

ボタンをクリックするたびに、カウントが上がっていく。

##説明
###コントローラクラス
MVC でいうところのコントローラに当たるクラス。
「AnchorPane」の「コントローラ・クラス」に指定した Java クラスが、その画面を制御するためのコントローラになる。

クラス自体は POJO でいい。

###コントローラクラスのフィールドと画面上のコンポーネントを紐付ける
ボタンなどのコンポーネントには `fx:id` という属性が指定できる。
その値と同じ名前のフィールドをコントローラクラスに作成し、 `javafx.fxml.FXML` アノテーションを付与すると、 fxml 上のコンポーネントとコントローラクラスのフィールドが紐付けられる。

```java:@FXMLアノテーションで紐付ける
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;

public class HelloController {
    @FXML private Button helloButton;
    @FXML private Label  helloLabel;
}
```

###イベントを紐付ける
ボタンの「On Action」に指定した名前と同名のメソッドをコントローラクラスに作成し、 `@FXML` アノテーションを付与すると、ボタンを選択したイベントとメソッドが紐付けられる。

```java:@FXMLアノテーションでイベントを紐付ける
import javafx.event.ActionEvent;
import javafx.fxml.FXML;

public class HelloController {
    @FXML
    public void onHelloButtonClicked(ActionEvent event) { 
        // イベント処理
    }
}
```

引数に `ActionEvent` を受け取るようにしているが、使わないのであれば引数無しでも紐付けは可能。

```java:引数無しでもOK
public class HelloController {
    @FXML
    public void onHelloButtonClicked() { 
        // イベント処理
    }
}
```

#コントローラクラスに初期化処理を記述する
画面表示時に初期化処理を実装したい場合は、コントローラクラスに `javafx.fxml.Initializable` インターフェースを実装させる。

```java:Initializableインターフェースを実装する
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;

public class HelloController implements Initializable {
    
    @FXML private Label  helloLabel;

    @Override
    public void initialize(URL url, ResourceBundle bundle) {
        this.helloLabel.setText("no click");
    }
}
```

`initialize(URL, ResourceBundle)` メソッドが画面表示時にコールバックされるので、ここに初期化処理を書けばいい。


#参考
+ [Java技術最前線 - JavaFX 2で始めるGUI開発　第1回 JavaFX 2とは：ITpro](http://itpro.nikkeibp.co.jp/article/COLUMN/20120731/413043/?ST=develop)
+ [Installed Java 7u9 and Eclipse (Juno) but Eclipse doest see JavaFX2 - Stack Overflow](http://stackoverflow.com/questions/13499779/installed-java-7u9-and-eclipse-juno-but-eclipse-doesnt-see-javafx2)