前回はとりあえずウィンドウを表示したが、今回はJavaFXプログラムの基本構造の理解とサンプルを用いてコーディング方法を理解することを目的とする。
■ 資料
まずは参考とした資料の紹介から。
- JavaFX テクノロジーの概要(Oracle公式)
- Java Platform, Standard Editionデプロイメント・ガイド(Oracle公式)
- JavaFX日本語情報源(torutkの日記)
Oracle公式サイトにはJavaDoc的なものやチュートリアルが存在する。チュートリアルが良い感じ。ただし、全編英語なので読むのがつらい。幸いにも、デプロイメント・ガイドは日本語版を発見できた。torutkさんのブログはJavaFXに関するリンク集がまとめられている。ただし、2012年の記事なのでちょっと情報が古い。
■ JavaFXアーキテクチャ
JavaFXは以下の4つのエンジンが基本となっている。しかし、プログラミングではあまり表に出てこないものなので、意識しないでいいらしい。
- グラフィック・エンジン(Prism)
- ウィンドウ制御エンジン(Glass)
- メディアエンジン
- ウェブエンジン
メディアエンジンでは音声・動画の処理を行う。対応するメディア・フォーマットは以下の通り。
- オーディオ:MP3, AIFF, WAV
- ビデオ:FLV,MPEG-4
■ JavaFXプログラムの基本構造
サンプルプログラムを紹介する前に、JavaFXプログラムの基本構造を押さえておく。一般的なスタンド・アローンのGUIプログラムを作成する場合、Applicationクラス内で以下のクラスをそれぞれ作成することで画面を作成する。
クラス |
役割 |
ステージ
(Stage) |
ウィンドウに対応するクラス。
デフォルトのステージ(トップレベル・コンテナ)インスタンスはApplicationクラス内で自動生成され、Startメソッドの引数として渡される。 |
シーン
(Scene) |
ウィンドウ内の表示領域に対応するクラス。
シーングラフを保持するためのコンテナであり、ウィンドウの表示領域のサイズとシーングラフのルート・ノードを決定する。 |
シーングラフ
(SceneGraph) |
表示オブジェクトに対応するクラス。シーン内に描写するすべてのオブジェクトのデータを保持する。 |
プログラマーが意識すべきは『シーングラフ(Scene Graph)』というクラスである。シーングラフは、アプリケーション上の表示オブジェクトがすべて格納されたTree構造のデータである。Tree構造の各ノードが表示オブジェクトであり、それぞれIDやCSSスタイル、イベントハンドラ等が設定可能となっている。シーングラフ内のノードは、Tree内でのノード位置により以下の3つに分類される。
- ルートノード(root node):シーングラフの根ノード。ノードで唯一、親を持たない
- 内部ノード(branch node):子を持つノード
- 葉ノード(leaf node):子を持たないノード
例えば、ウィンドウ内に円を描きたい場合は、円クラスのインスタンスをシーングラフに追加すればよい。JavaFXアプリケーション構築はこのシーングラフの構築から始まる。しかし、シーングラフはデータの集合でしかないので、実際に描画されなければウィンドウに表示されることはない。では、どのようにシーングラフのデータを描画するか。
JavaFXの描画方式は『パルス(Pulse)という再描画イベントが発生することにより、グラフィック・エンジンが自動で描写する』という形になっている。パルスとは60fpsを上限とした再描画イベントである。再描画イベントはエンジンが判断し、自動発生する。このため、プログラマはシーングラフにデータを登録するだけで、ウィンドウにデータが自動描画されるように見える。
SwingやAWTに慣れた人は『プログラマーが実装した再描画メソッド(paintメソッド)を、再描画イベントが発生した瞬間に呼び出すことで描画する』という方式に慣れているが、JavaFXでは少し異なる点に注意が必要となる。
■ サンプルプログラム
ここでは、
前回の記事で作成した新規プロジェクトのソースコードに少し手を加えたサンプルを例に、コーディング方法を確認する。実行結果とソースコードは以下の通りである。
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
// シーングラフを作成
BorderPane root = new BorderPane();
// シーングラフに子ノードを追加する
Rectangle r = new Rectangle(10,20,100,200);
r.setFill(Color.YELLOW);
root.getChildren().add(r);
// シーンを作成
Scene scene = new Scene(root,400,400,Color.BLACK);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
// ステージにシーンを登録し、ウィンドウ表示する
primaryStage.setScene(scene);
primaryStage.setTitle("JavaFX Hellow World!");
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
上記のサンプルを説明すると…
- プログラムはApplication.Mainメソッドからスタート
- MainメソッドではApplication.launchメソッドを呼び出す
- launchメソッドによりStartメソッドが呼び出される
- シーングラフを作成(15行目~)(ここではルートノードがBorderPaneクラスで、子ノードがRectangleクラス)
- シーンの作成(23行目~)。作成時にシーングラフとウィンドウサイズ(幅、高さ)、背景色を指定
- ステージにシーンを関連付けて、ウィンドウの表示を開始(27行目~)
という感じである。LOCが小さいためJavaFXならではのメリットは感じられないが、難しいということはないと感じる。
■ JavaFX の特徴
最後に、Oracleのチュートリアルの中で注目したJavaFXの特徴を記しておく。
- ロジックとUIデザインの分離
- 主要プラットフォーム(Windows, Mac OS X, Linux)に対応
- ハードウェアを用いた描写高速化(Prism)
- 自己完結型アプリケーションが作成可能
1.については、ルックアンドフィールはCSSで、UIコンポーネントの配置はFXMLスクリプト(XML)で指定することで、ロジックとUIデザインの分離を可能としている。また、JavaFX Scene BuilderというIDEを利用することで、FXMLの記述は必要なくGUIでデザイン可能となるらしい。
2.については、Java最大のメリットは一つのソースコードがクロスプラットフォームで同じ動作する点と個人的に感じているため、どのレベルで実現されているかは期待したいところ。
3.についても期待したいが注目したのは、リッチテキストサポートとして複数行テキスト描写がサポートされたとのこと。これまでは実装することが面倒だったため手をだせていなかったため嬉しい。
4.については初めて聞いたが一般的な用語なのだろうか。自己完結型アプリケーションとはexeファイルのようにJava環境がないPCでも動くアプリケーションを示すらしい。実装としてはJREも含んだJarファイルとなっているらしい。JREがインストールできない環境では有効と思われる。
■ 参照リンク
- JavaFX: Getting Started with JavaFX(1 JavaFX Overview)
- JavaFX: Getting Started with JavaFX(2 Understanding the JavaFX Architecture)
- JavaFX: Working with the JavaFX Scene Graph
- JavaFX: API