はじめに
少し前にJavaでGUIツールを作ろうとしたとき、JavaFXを勉強しました。
その時の備忘を兼ね、JavaFXの初めの一歩を踏み出すための基本をこちらの記事に書き記しておきます。
1. JavaFXとは
JavaでGUIアプリケーションを作る時に便利なフレームワークです。
少し前に登場したJavaの新機能で、そんなにホットな技術ではないのですが、結構知らない人も多いらしく意外とマイナーです。
こちらの記事をたまたま目にした方も、「JavaでGUIと言えば、SWING!」と思ってはいませんか?
いえいえ、それが最近は違うらしいのです。
筆者の勝手な思いですが、SWINGからJavaFXへ進化して、GUIアプリケーションのハードルが革命的に低くなりました。
そんな便利な技術、JavaFXの世界をほんの始めですが、ご紹介していきますので、今日にある方は続きをご覧ください。
2. 環境構築
何を作るにもまずやらなければならないのが、環境構築です。
なので、まずはJavaFXアプリケーションが開発できる環境を用意しましょう。
JavaFXは、最低限Eclipseがあれば、JavaFX開発用のプラグインを導入することで開発可能です。
しかし、これだけだと結構しんどいので、scene builderというものをインストールしましょう。
こちらを使えば、GUIのドラッグアンドドロップでJavaFXの画面を構築できます。
SWINGの時代から似たようなものはありましたが、あまり使い勝手がよいものはなかったように思いますが、このツールは、ものすごく使い勝手がいいので、ぜひインストールしてください。
2.1. Eclipseプラグインの導入
まずは、EclipseでJavaFXプロジェクトを作るためのプラグインを導入します。
ヘルプ > Eclipseマーケットプレースの検索ボックスに、「javafx」と入力し、検索します。
検索結果から、「e(fx)clipse」というプラグインをインストールしてください。
筆者の環境では、Eclipse4.4にプラグインを導入しています。
2.2. Scene Builderのインストール
先に記載した、Scene Builderをインストールします。
Oracleの公式WebからScene Builder2のインストーラをダウンロードし、インストールしてください。
他にもScene Builderという名前で同じ機能を持ったツールを配布しているところもありますが、いったん今回は公式からダウンロードすることとしましょう。
インストール後、起動すると、次のような画面が出現すると思います。
2.3. プロジェクトの構築
Eclipse上に開発用のプロジェクトを構築します。
2.1.の手順を実施していれば、プロジェクトの新規作成ダイアログの中に、「JavaFX Project」が存在するはずなので、そこからプロジェクトを作成します。
3. 画面の作成
JavaFXでは、画面をXMLファイルで作成します。
筆者が革命的に便利だと感じる、最大の理由がこの機能です。
これまでは、Javaのプログラムコードをガリガリと書いて、画面を作っていきましたが、JavaFXでは、あらかじめXMLで画面を作っておき、それを読み込むことでアプリケーションで使用する画面を表示します。
この機能によって、アプリケーションの画面がHTMLのような感覚で、直観的にイメージしながら、作ることができます。
さらに、XMLファイルの作成には、先ほどをインストールしたScene Builderでドラッグアンドドロップで作ることができるので、本当に楽に構築できます。
3.1. FXMLファイルの作成
前置きが長くなってしまいましたが、具体的な手順に移っていきましょう。
まずは、インストールしたScene Builderを起動し、画面を作っていきましょう。
今回は、最終的に次のような簡単な画面を作ります。
起動すると、先に記載したようなグレーの画面が現れると思いますが、その上に、左からパーツをドラッグ&ドロップします。
すると、Scene Builder内で、その操作がXMLとして記録されますので、それをプロジェクトの使用します。
上記の画面を作ると、次のようなXMLファイルが出来上がりますので、XMLの記載通りにScene Builderをいじってみてください。
<?xml version="1.0" encoding="UTF-8"?>
<!-- FXMLファイルには使用するクラスはimportが必要 -->
<?import javafx.collections.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import ctrl.Controller?>
<?import javafx.collections.FXCollections?>
<?import javafx.collections.ObservableList?>
<!-- 一番外側のパーツにコントローラに使用するクラスを指定する -->
<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ctrl.Controller">
<!--
今回はAnchorPaneというパーツを置く入れ物を使用します。
JavaFXにはほかにもPaneはありますが、AnchorPaneは結構便利です。
特別な用途がない場合は、AnchorPaneは大活躍します。
-->
<children>
<VBox AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="5.0">
<children>
<!--
Paneは入れ子にできます。
今回は、画面のパーツをある程度決まった間隔に置くために、
GridPaneを使用しています。
-->
<GridPane hgap="3.0" vgap="1.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="250.0" minWidth="196.0" prefWidth="243.0" />
<ColumnConstraints hgrow="SOMETIMES" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<!-- テキストのLabelは特に拾うイベントもないのでidは指定しません -->
<Label text="ドロップダウン:" GridPane.halignment="RIGHT">
<GridPane.margin>
<Insets />
</GridPane.margin>
</Label>
<Label text="テキストボックス:" GridPane.halignment="RIGHT" GridPane.rowIndex="1" />
<!-- FXML内のパーツはfx:id属性で一意に識別できるIDを割り当てる -->
<ChoiceBox fx:id="dropDown" prefWidth="150.0" GridPane.columnIndex="1" GridPane.halignment="LEFT">
<GridPane.margin>
<Insets />
</GridPane.margin>
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="アイテム1" />
<String fx:value="アイテム2" />
</FXCollections>
</items>
</ChoiceBox>
<!--
クリックなどのイベントを拾って処理したい場合は、
onAction属性でイベント時のアクションを行うメソッドを指定します。
アクションの処理は、先頭で指定したコントローラーに実装します。
-->
<Button fx:id="button" mnemonicParsing="false" onAction="#onClick" text="ボタン" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1" />
<TextField fx:id="textBox" GridPane.columnIndex="1" GridPane.rowIndex="1">
<GridPane.margin>
<Insets />
</GridPane.margin>
</TextField>
</children>
</GridPane>
</children>
</VBox>
</children>
</AnchorPane>
「長い!」と思われる方もいらっしゃるでしょうが、今この記事を執筆している時点では、ちょっと時間がないので、スクリーンショット付きのきれいな記事にはできません。
時間ができたらアップデートしますので、それまで、しばらくお待ちください。
4. JavaFXアプリケーションの構築
それでは、画面のレイアウトができたところで、作ったレイアウトを使用した画面を持つアプリケーションを構築していきましょう。
プロジェクトは、先ほど新規作成したJavaFXプロジェクトを使用します。
最終的なツリーは次のようになります。
■プロジェクトツリー
プロジェクトルート
└─src
├─application
│ application.css
│ Main.fxml
│ Main.java
│
└─ctrl
Controller.java
4.1. 起動処理
まずは、先ほどのXMLを読み込むための起動処理を実装します。
JavaFXの起動は、main処理で行います。
今回は、Mainという名のクラスに、main処理を実装します。
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/*******************************************
* 画面
* @author tarosa0001
*******************************************/
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
// FXMLのレイアウトをロード
Parent root = FXMLLoader.load(
getClass().getResource(getClass().getSimpleName() + ".fxml"));
// タイトルセット
primaryStage.setTitle("JavaFXSample");
// シーン生成
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
4.2. コントローラの実装
続いて、コントローラーを実装していきます。
JavaFXでは、ボタンクリックなどのイベントをハンドリングし、イベントごとに適した処理を提供するクラスを「コントローラー」と呼びます。
原則、コントローラーは、画面に定義しているすべてのパーツのオブジェクトを保持し、そのパーツに適した処理を実装します。
ただのテキストラベルのように、クリックイベントも何もないようなパーツでも、必ずコントローラーにはオブジェクトを定義する必要があります。
先ほど構築したXMLレイアウトを持つ画面に対するコントローラーは次のようになります。
今回はサンプルなので、ほとんど処理はしていません。
package ctrl;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TextField;
/***********************************************
* 画面のコントローラー
* @author tarosa0001
***********************************************/
public class Controller implements Initializable {
/** ドロップダウン */
@FXML
private ChoiceBox<String> dropDown;
/** テキストフィールド */
@FXML
private TextField textBox;
/** ボタン */
@FXML
private Button button;
/** ************************************************************
* 初期化処理
* 画面表示時に行いたい処理を実装する。
* @param location
* @param resources
* *************************************************************/
@Override
public void initialize(URL location, ResourceBundle resources) {
// 何もしない
}
/** ************************************************************
* ボタン押下時のアクション
* @param event イベント
* *************************************************************/
@FXML
public void onClick(ActionEvent event) {
// テキストボックスに文字列をセットする
textBox.setText("ボタンを押しました。");
}
/** ************************************************************
* ツールタイプ選択ドロップダウンを取得します。
* @return ツールタイプ選択ドロップダウン
* *************************************************************/
public ChoiceBox<String> getToolType() {
return dropDown;
}
/** ************************************************************
* ツールタイプ選択ドロップダウンを設定します。
* @param toolType ツールタイプ選択ドロップダウン
* ************************************************************/
public void setToolType(ChoiceBox<String> toolType) {
this.dropDown = toolType;
}
/** ************************************************************
* 入力ファイル名テキストフィールドを取得します。
* @return 入力ファイル名テキストフィールド
* ************************************************************/
public TextField getInputFile() {
return textBox;
}
/** ************************************************************
* 入力ファイル名テキストフィールドを設定します。
* @param inputFile 入力ファイル名テキストフィールド
* ************************************************************/
public void setInputFile(TextField textBox) {
this.textBox = textBox;
}
/** ************************************************************
* 参照ボタンを取得します。
* @return 参照ボタン
* ************************************************************/
public Button getReference() {
return button;
}
/** ************************************************************
* 参照ボタンを設定します。
* @param reference 参照ボタン
* ************************************************************/
public void setReference(Button button) {
this.button = button;
}
}
少し長くなりましたが、今回はgetterとsetterも実装しています。
イベント時にアクションがあるのは、このコントローラーではボタンのクリック時のみですが、イベントを拾った際のアクションは、FXMLのonAction属性で指定します。
5. アプリケーションの実行
それでは、ここまでで構築したアプリケーションを実行してみましょう。
実行方法は、通常のJavaアプリケーションのと同じです。
実行時のパスなどの設定は特に必要ありませんので、Eclipse上でJavaアプリケーションとして実行してみましょう。
するといかがでしょう?先ほどまで構築した画面がでてきました。
この状態でボタンを押すと、コントローラー実装した処理が実行され、テキストボックスにテキストが入ります。
もちろんドロップダウンにも、FXMLで3設定した初期値が設定されています。
次に実行例を記載します。
6. 最後に
ここまででものすごく基本的なJavaFXアプリケーションの構築方法をご紹介してきましたが、いかがでしょうか?
AWTはSWINGに比べて、HTMLで画面を書くような間隔で画面を実行できるので、レイアウトの入れ子などが見やすくなっているのではないでしょうか。
GUIアプリケーションと言うと画面の構築がものすごく面倒くさいイメージですが、画面のレイアウトもツールで作ることができれば、そのハードルはぐっと下がります。
場合によっては、FXMLを直に編集したほうが早いこともあるんですけどね(^^;
今までは、ちょっとした作業を自動化しようと思ったりしたときは、ExcelでVBAを使ったり、コンソールアプリケーションを実装するのが定石だったと思いますが、それらでは限界があったり、逆に手間がかかったりすることもありました。
その点JavaFXアプリケーションは、画面構築の手軽さと、Javaの機能を全て使えるという利点があります。
機会があれば、さくっとツールでも作って、面倒な作業を自動化してみてはいかがでしょうか。
EX. 参考
筆者も参考にさせていただいたWebページのリンクを記載します。
■JavaFXでHelloWorld
http://qiita.com/opengl-8080/items/de390c063db52e04b591