1 JavaFXシーン・グラフの操作
このチュートリアルでは、グラフィカル・ユーザー・インタフェース(GUI)を画面に表示するための基盤となるフレームワークである、JavaFXシーン・グラフ・アプリケーション・プログラミング・インタフェース(API)について説明します。
Java開発者としての経験がある場合は、これまでにグラフィカル・ユーザー・インタフェースを含むアプリケーションを作成したことがある可能性が高いと思われます。これは、Webページ内の小さいプログラムから、デスクトップ上のスタンドアロンSwingアプリケーションまで、どのようなものでもかまいません。また、カスタム・ペインティングを行ったことがある場合は、Graphics
クラスとその関連メソッドに精通しているはずです。従来のアプローチは強力ですが、グラフィックを画面に正しくレンダリングするために、開発者側で常にある程度の労力が必要でした。多くの場合、この作業は大部分のアプリケーション・ロジックから切り離されています。
概要
JavaFXシーン・グラフAPIは、特に、複雑な視覚効果と変換が含まれる場合に、グラフィカル・ユーザー・インタフェースの作成を容易にします。シーン・グラフとは、ベクター編集ツール、3Dライブラリ、ビデオ・ゲームなどのグラフィカルなアプリケーションおよびライブラリで最も一般的に使用されるツリー・データ構造です。JavaFXシーン・グラフは保持モードAPIで、アプリケーション内のすべてのグラフィカル・オブジェクトの内部モデルが保持されます。指定された時間に、どのオブジェクトを表示し、画面上のどの領域を再描画する必要があり、どのようにそれらすべてを最も効果的な方法でレンダリングできるかの情報が保持されます。プリミティブ描画メソッドを直接コールするかわりに、シーン・グラフAPIを使用して、レンダリングの詳細をシステムで自動的に処理できます。このアプローチにより、アプリケーションで必要となるコードの数が大幅に削減されます。
JavaFXシーン・グラフ内に保持される個々のアイテムは、ノードと呼ばれます。各ノードは、ブランチ・ノード(子を持つことができる)またはリーフ・ノード(子を持つことができない)に分類されます。ツリーの最初のノードは常にルート・ノードと呼ばれ、親を持つことはありません。一般的な継承ダイアグラムは、図1-1を参照してください。
JavaFX APIは、ルート、ブランチまたはリーフ・ノードとして機能できるクラスの数を定義します。実際のクラス名に置き換えた場合、これと同じ図は、実際のアプリケーションでは図1-2のようになります。
図1-2では、Group
オブジェクトがルート・ノードとして機能します。Circle
オブジェクトとRectangle
オブジェクトは、子を持たない(持てない)ため、リーフ・ノードです。Region
オブジェクト(CSSを使用してスタイルを設定できる子を含む画面領域を定義する)は、2つのリーフ・ノード(Text
およびImageView
)を含むブランチ・ノードです。シーン・グラフはこれよりはるかに大きくなる可能性がありますが、基本的な編成、つまり、親ノードがどのように子ノードを含むかは、すべてのアプリケーションで繰り返されるパターンです。
APIの説明
それでは、コードでは、これは何を意味するのでしょうか。まず、例1-1に示すように、ルート・ノードのみが移入された基本的なアプリケーション・フレームを設定します。
例1-1 アプリケーション・フレームの作成
package scenegraphdemo; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage stage) { Group root = new Group(); Scene scene = new Scene(root, 500, 500, Color.BLACK); stage.setTitle("JavaFX Scene Graph Demo"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
このコードは、図1-3に示されているようなウィンドウを生成します。
考慮する必要がある重要な点は、次のとおりです。
-
Main
クラスは、javafx.application.Application
クラスの拡張です。そのstart
メソッドはオーバーライドされ、唯一のパラメータとしてStage
オブジェクト(最上位レベルのGUIコンテナ)を受け取ります。 -
ルート・ノード(この例では、
javafx.scene.Group
クラスのインスタンス)が作成され、シーンの幅、高さおよび塗りつぶしとともに、シーンのコンストラクタに渡されます。 -
ステージのタイトル、シーンおよび可視性はすべて設定されています。
-
mainメソッドにより、
Application.launch()
メソッドが呼び出されます。
生成されるアプリケーションは、シーンの塗りつぶし色が黒であるため、そのままの見た目で表示されます。現時点ではルート・ノードに子がないため、それ以外は何も表示されません。ルート・ノードへの子の追加は、例1-2に示されている変更によって実行できます。
例1-2 リーフ・ノードの追加
package scenegraphdemo; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage stage) { Group root = new Group(); Scene scene = new Scene(root, 500, 500, Color.BLACK); Rectangle r = new Rectangle(25,25,250,250); r.setFill(Color.BLUE); root.getChildren().add(r); stage.setTitle("JavaFX Scene Graph Demo"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
例1-2に示されている変更により、250x250ピクセルの青い四角形(リーフ・ノード)が、指定されたXおよびY座標に表示されます。(デフォルトでは、Xは左から右へと大きくなり、Yは上から下へと大きくなります。ただし、これは変換によって影響を受けます。)図1-4に、リーフ・ノードを追加した結果を示します。
グラフィカル・オブジェクトはシーン・グラフによって管理されるため、ほんのわずかな追加コードのみで、興味深い効果を実現できます。たとえば、四角形が回転しながらそのサイズを変え、色を青から赤に遷移しながら画面全体を往復するように、簡単にアニメーション化できます。
例1-3では、これを実現するために遷移を使用しています。
例1-3 シーンのアニメーション化
package scenegraphdemo; import javafx.animation.FillTransition; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.stage.Stage; import javafx.animation.Timeline; import javafx.animation.ParallelTransition; import javafx.animation.RotateTransition; import javafx.animation.ScaleTransition; import javafx.animation.TranslateTransition; import javafx.util.Duration; public class Main extends Application { @Override public void start(Stage stage) { Group root = new Group(); Scene scene = new Scene(root, 500, 500, Color.BLACK); Rectangle r = new Rectangle(0, 0, 250, 250); r.setFill(Color.BLUE); root.getChildren().add(r); TranslateTransition translate = new TranslateTransition(Duration.millis(750)); translate.setToX(390); translate.setToY(390); FillTransition fill = new FillTransition(Duration.millis(750)); fill.setToValue(Color.RED); RotateTransition rotate = new RotateTransition(Duration.millis(750)); rotate.setToAngle(360); ScaleTransition scale = new ScaleTransition(Duration.millis(750)); scale.setToX(0.1); scale.setToY(0.1); ParallelTransition transition = new ParallelTransition(r, translate, fill, rotate, scale); transition.setCycleCount(Timeline.INDEFINITE); transition.setAutoReverse(true); transition.play(); stage.setTitle("JavaFX Scene Graph Demo"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
これらの例は単純ですが、ほとんどのグラフィカル・アプリケーションで使用されるいくつかの重要な概念を示し、デモンストレーションしています。
javafx.scene
パッケージは13以上のクラスを定義しますが、APIの構造の理解においては、特に次の3つが最も重要です。
-
Node
: すべてのシーン・グラフ・ノードの抽象ベース・クラス。 -
Parent
: すべてのブランチ・ノードの抽象ベース・クラス。(このクラスはNode
を直接拡張します)。 -
Scene
: シーン・グラフのすべてのコンテンツのベース・コンテナ・クラス。
これらのベース・クラスは、ペイント順序、可視性、変換の構成、CSSスタイル設定のサポートなど、サブクラスによって後から継承される重要な機能を定義します。また、Control
、Group
、Region
、WebView
など、様々なブランチ・ノードのクラスがParent
クラスから直接継承します。リーフ・ノードのクラスは、javafx.scene.shape
、javafx.scene.text
などのいくつかの追加パッケージで定義されます。