ついにベールを脱いだJavaFX

第4回シェイプで遊ぶ

第2回で作成したHello, World!だけでは、JavaFX Scriptの実力を知ることはできません。そこで、今回はUI、特にグラフィックの描画に関する機能を紹介していきます。

とはいうものの、第2回で使用したNetBeansは英語版なので、ちょっとしきいが高いですね。そこで、今回からは日本語版のNetBeansにJavaFX Pluginをインストールして、使用していきます。

JavaFX Pluginのインストール

すでにインストールされているNetBeansに後からJavaFX Pluginをインストールする手順は、他のプラグインをインストールする時と同じです。残念ながら、JavaFX Pluginはまだ日本語化されていないので、JavaFXに関する部分は英語のまま表示されます。

インストールを行うには、まずNetBeansを起動します。そして、メニューバーの[ツール]の項目の中から[プラグイン]を選択します。すると、プラグインダイアログが表示されます。ダイアログの上部にあるタブの中から[使用可能なプラグイン]を選択すると、使用可能なプラグインのリストが表示されます。このリスト中に、JavaFX関連のプラグインが4種類あります。

  • JavaFX Source Debug
  • JavaFX 1.0
  • JavaFX SDK for Windows
  • JavaFX Weather Sample

3番目のJavaFX SDK for Windowsは、もちろんWindowsで実行した場合のものです。MacではMac用のSDKが表示されます。

図1のように、これらのプラグインにチェックをし、ダイアログの下の方にある[インストール]ボタンをクリックします。

図1 JavaFX Pluginの選択
図1 JavaFX Pluginの選択

すると、図2のように確認画面が表示されるので、⁠次へ >]をクリックして、先に進めます。

図2 プラグインの確認
図2 プラグインの確認

次に表示されるのが、ライセンス契約です。ライセンス条項を確認してから、下部にある[すべてのライセンス契約条件に同意する]にチェックをし、⁠インストール]をクリックします。

図3 ライセンス契約
図3 ライセンス契約

インストールには数分かかりますので、必要に応じて図4[バックグラウンドで実行]をチェックしてください。このチェックをすることで、インストール作業が行われているにもかかわらず、他の作業を行うことができます。

図4 インストール画面
図4 インストール画面

インストールが完了すると、NetBeanの再起動を求められます。再起動を行えば、JavaFXを使用することができます。

図5 プラグインのインストール完了画面
図5 プラグインのインストール完了画面

サンプルプロジェクトの実行

インストールが正常にできているか確かめるため、JavaFXのサンプルを動かしてみましょう。

まず、メニューバーの[ファイル]から[新規プロジェクト]を選択します。すると、図6のようにプロジェクトのカテゴリや種類を選択するダイアログが表示されます。⁠カテゴリ]のサンプルを展開するとJavaFXのサンプルが表示されます。ここでは図6に示したようにPhoto Effectsを選択しました。

図6 プロジェクトの選択
図6 プロジェクトの選択

[次へ >]をクリックして先に進めます。次にプロジェクトの名前とロケーションを選択する画面です図7⁠。この画面からJavaFX Pluginによる表示なので、英語表記になってしまいます。プロジェクト名、ロケーション共にデフォルトのままでかまいません。⁠完了]をクリックすると、プロジェクトが作成されます。

図7 プロジェクトの名前およびロケーションの選択
図7 プロジェクトの名前およびロケーションの選択

プロジェクトを作成すると、プロジェクトペインに表示されます。PhotoEffectsプロジェクトは2つのJavaFX Scriptファイルから構成されています図8⁠。JavaFX Scriptのスクリプトファイルは拡張子が.fxとなります。もう1つのphotoeffects.imageパッケージはアプリケーションで使用するイメージが配置されています。

図8 PhotoEffectsプロジェクトの構成
図8 PhotoEffectsプロジェクトの構成

では、PhotoEffectsを実行してみましょう。実行するにはプロジェクトペインのプロジェクト名、ここではPhotoEffecttsを右クリックしてポップアップメニューを表示させます図9⁠。表示されたメニューの中から、⁠Run Project]を選択すると、プロジェクトが起動します。

プロジェクトが主プロジェクトであれば、メニューバーの[実行]から[主プロジェクトを実行⁠⁠、もしくはファンクションキーのF6を押すことでも実行することができます。

図9 プロジェクトの実行
図9 プロジェクトの実行

実行すると図10に示すウィンドウが表示されます。このアプリケーションはキリンのイメージの明るさやコントラストを上部のスライダーで調節するアプリケーションです。実際にスライダーを動かして、イメージを調節してみてください。

図10 PhotoEffectsの実行結果
図10 PhotoEffectsの実行結果

この連載ではこれ以降、日本語版NetBeansにJavaFX Pluginをインストールしたものを使っていきます。

円、四角、文字…シェイプ

プロジェクトの生成

今回取りあげるのは、円や四角などを描画する機能です。円や四角などは⁠シェイプ⁠と呼ばれ、すべてjavafx.scene.shape.Shapeクラスのサブクラスとして定義されています。シェイプとして提供されている主なクラスを次に示します。

  • Arc 円弧、扇形
  • Circle 円
  • CubicCurve 3次パラメトリック曲線(ベジェ曲線)
  • Ellipse 楕円
  • Line 直線
  • Path 直線、曲線からなるパス
  • Polygon 多角形
  • PolyLine 複数の直線
  • QuadCurve 2次パラメトリック曲線(スプライン曲線)
  • Rectangle 四角形/角丸四角

ここでは、Circleクラスを使って円を描画してみましょう。

  • サンプルコードはこちらからダウンロードしてください:circlesample.zip

では、まずプロジェクトを作成します。先ほどと同じように、NetBeansのメニューバーから[ファイル]を選択し、⁠新規プロジェクト]をクリックします。今回は、プロジェクトのカテゴリをJavaFX、プロジェクトをJavaFX Script Applicationを選択します図11⁠。

図11 プロジェクトの選択
図11 プロジェクトの選択

次にプロジェクト名などを選択する画面に移ります。ここでは、円を描画するサンプルなので、プロジェクト名はcirclesampleとしました。メインファイルは作成せずに、後から作成するようにしました。したがって、図12のように[Create Main File]のチェックは外しておきます。

図12 プロジェクトの設定
図12 プロジェクトの設定

作成したプロジェクトは空のプロジェクトです。そこで、まずスクリプトファイルを作成しましょう。図13に示したようにプロジェクトペインのcirclesampleプロジェクトを右クリックし、ポップアップメニューを表示させます。メニューの[新規]にはさまざまな種類の項目がリストアップされています。ここでは[Empty JavaFX File...]を選択します。

図13 JavaFX Scriptファイルの作成
図13 JavaFX Scriptファイルの作成

すると、スクリプトのファイル名などを設定するダイアログが表示されます図14⁠。ここではスクリプトのファイル名をcirclesampleにしました。最下部に表示されている警告はパッケージを設定していないためです。まぁ、ここではあまり気にしないでおきましょう。ファイル名を記入したら、⁠Finish]をクリックしてファイルを作成します。

図14 スクリプトファイル作成ダイアログ
図14 スクリプトファイル作成ダイアログ

コードパレットを使用したコードの作成

スクリプトファイルを作成すると、自動的にエディタに表示されます。JavaFX Scriptファイルをエディタで表示すると、エディタの右側にコードパレットが表示されます。図15の赤い四角で囲まれた領域がコードパレットです。このコードバレットを使用することで、コードのひな形を作成してくれます。このため、比較的簡単にスクリプトを作成することができるのです。

図15 コードパレット
図15 コードパレット

コードパレットにはApplicationsやAction、Basic Shapesなどのカテゴリがあり、それぞれのカテゴリにいくつかの項目が含まれています。

では、実際にコードパレットを使用してみましょう。まずは、SwingのJFrameクラスに相当する、Stageクラスを使用してアプリケーションの大枠を作ってしまいましょう。StageはコードパレットのApplicationに含まれています。Stageをドラッグして、エディタの図16に示した箇所にドロップします。

図16 Stageをドラッグ&ドロップする
図16 Stageをドラッ

Stageをドロップすると、次のようなコードがエディタに表示されます。

リスト1 circlesample.fx
import javafx.stage.Stage;
import javafx.scene.Scene;
/*
 * circlesample.fx
 *
 * Created on 2008/12/06, 15:13:59
 */
 
  
 /**
 * @author sakuraba
 */
 
 // place your code here
Stage {
    title: "MyApp"
    scene: Scene {
        width: 200
        height: 200
        content: [  ]
    }
}

赤字で示した部分がStageをドロップしたことによるコードです。このコードはStageオブジェクトを生成し、titleアトリビュートに"MyApp"、sceneアトリビュートに新たにSceneオブジェクトを生成して代入しています。Sceneオブジェクトは幅と高さが200ピクセル、contentアトリビュートは空のままです。

まずは、このスクリプトを実行してみましょう。先ほどと同じように、プロジェクト名を右クリックして表示されたポップアップメニューから[Run Project」を選択して実行します。ここでは、メインスクリプトファイルを設定していないので、メインスクリプトファイルを設定するためのダイアログが表示されます図17⁠。そこで、circlesample.fxを選択して[OK]をクリックすれば、実行されます。

このダイアログはメインスクリプトファイルを設定していない場合のみ表示されるので、2回目の実行からは表示されません。

図17 メインスクリプトファイルの選択
図17 メインスクリプトファイルの選択

通常の方法で起動するのでもかまわないのですが、エディタに表示されているスクリプトファイルを実行するだけであれば他の方法もあります。それはメニューバーの[実行]から[ファイルを実行]を選択するか、シフトキーを押しながらファンクションキーのF6を押す方法です。

スクリプトを実行した結果を図18に示しました。単に真っ白のウィンドウが表示されるだけです。

図18 circlesample.fxの実行結果
図18 circlesample.fxの実行結果

では、次に円を描画するコードを、コードパレットからドロップしましょう。円はコードパレットのBasic Shapesの中にあるCircleです。これをドラッグして、Sceneオブジェクトのcontentアトリビュートに代入している空のシーケンスの中にドロップします図19⁠。

図19 Circleのドラッグ&ドロップ
図19 Circleのドラッ

Circleをドロップすると、次のようなコードが生成されます(import文、コメントは省略しています⁠⁠。

リスト2
Stage {
    title: "MyApp"
    scene: Scene {
        width: 200
        height: 200
        content: [ Circle {
                centerX: 100, 
                centerY: 100
                radius: 40
                fill: Color.BLACK
} ]
    }
}

ちょっと見にくいので整形しましょう。コードの整形はエディタ部分を右クリックして表示されるポップアップメニューから[整形]を選択するか、Alt キーとShift キーとF キーを同時に押せばできます。しかし、整形能力はそれほど強力ではありません。とりあえず試してみて、思ったように整形されなければ、手作業で直すようにしましょう。

整形した結果を次に示します。

リスト3
Stage {
    title: "MyApp"
    scene: Scene {
        width: 200
        height: 200
        content: [ 
            Circle {
                centerX: 100, 
                centerY: 100
                radius: 40
                fill: Color.BLACK
            }
        ]
    }
}

円はjavafx.scene.shape.Circleクラスで表されます。Circleクラスのアトリビュートには中心位置を表すcenterXアトリビュートとcenterYアトリビュート、半径を表すradiusなどがあります。また、塗りつぶす色を指定するにはfillアトリビュート、円の線の色を指定するにはstrokeアトリビュートを指定します。

コードパレットで生成されるコードではcenterXとcenterYが100、半径が40になっています。fillとstrokeは色を表すjavafx.scene.paint.Colorクラスで指定します。Colorクラスには100種類を超える色がすでに定義されています。詳しくはAPIドキュメントをご覧ください。ここではfillに黒を表すColor.BLACKを指定しています。

では、このスクリプトを実行してみましょう。図20に実行結果を示します

図20 circlesample.fxの実行結果
図20 circlesample.fxの実行結果

コードのカスタマイズ

黒の円では味気ないので、アトリビュートを編集してみましょう。

JavaFX Pluginは補完機能を持っているため、コードを記述するのも容易です。ここでは、fillの次の行にstrokeアトリビュートを追加しましょう。s を入力した時点でCtrlキーとスペースキーを同時に押します。すると、図21のように使用できる候補が表示され、候補の説明も上部に表示されます。

図21 コードの補完機能
図21 コードの補完機能

ここでは、リストの中からstrokeを選択します。ここでは、線の色にColor.SKYBLUE、塗りつぶし色にColor.PALETURQUOISEを選びました。

リスト4
Stage {
    title: "MyApp"
    scene: Scene {
        width: 200
        height: 200
        content: [ 
            Circle {
                centerX: 100,
                centerY: 100
                radius: 40
                fill: Color.PALETURQUOISE
                stroke: Color.SKYBLUE
            }
        ]
    }
}

さて、ここで実行をおこなってもいいのですが、もっと簡単にスクリプトを確認する方法もあります。その方法はプレビューを使用する方法です。プレビューは図22に示したエディターペインの上部にあるアイコンの中から、一番左にあるアイコンをクリックします。

図22 プレビューアイコン
図22 プレビューアイコン

すると、Design Previewというウィンドウが表示され、その中にスクリプトのプレビューが表示されます図23⁠。このプレビューはスクリプトを変更すると、それに追随して表示が更新されます。

図23 スクリプトのプレビュー
図23 スクリプトのプレビュー

複数の円を描画する

1つの円だけでなく、円をいっぱい描いてみましょう。前回、シーケンスの生成にfor文を使用する方法を紹介しましたが、ここではそれを利用します。

リスト5
Stage {
    title: "Circle Sample"
    scene: Scene {
        width: 200
        height: 200
        
        content: [
            for (i in [0..99]) {
                // 乱数を使って場所や半径を決める
                var rand = new Random();
                
                Circle {
                    centerX: rand.nextInt(200)
                    centerY: rand.nextInt(200)
                    radius: rand.nextInt(30)
                    // RGBA で色を指定
                    fill: Color.rgb(175, 238, 238, 0.6)
                    stroke: Color.SKYBLUE
                }
            }
        ]
    }
}

赤字で示したように、for文を使用して100回のループを回すことで、要素が100個あるシーケンスを生成できます。要素はすべてCircleオブジェクトですが、位置や半径は乱数で決めています。変数randはJavaのjava.util.Randomクラスのオブジェクトです。import文は必要ですが、newを使用して生成し、JavaFX Scriptのオブジェクトのように扱うことができます。

ここでは、円の塗りつぶし色をRGBと透明度で指定しました。線の色は前と同じColor.SKYBLUEです。では、このサンプルを実行してみましょう図24⁠。

図24 複数の円の描画
図24 複数の円の描画

泡のように見えますか?

このサンプルでは直接中心座標と半径を乱数で設定していました。これ以外に、基本となる円を作成し、それを移動、拡大・縮小するという方法もあります。移動や拡大・縮小を行うには、transformXやscaleXのようなアトリビュートを使用するか、transformsアトリビュートを使用するという2つの方法があります。

transformsアトリビュートはjavafx.scene.transform.Transformクラスのシーケンスとして定義されています。Transformクラスは変換のためのスーパークラスで、サブクラスには次のようなクラスがあります。

  • Affine : アフィン変換
  • Rotate : 回転
  • Scale : 拡大・縮小
  • Shear : シアー
  • Translate : 移動

ここではtransformsアトリビュートを使用することにしましょう。まず、スクリプトを以下のように変更します。

リスト6
Stage {
    title: "Circle Sample"
    scene: Scene {
        width: 200
        height: 200
 
        content: [
            for (i in [0..99]) {
                // 乱数を使って場所や半径を決める
                var rand = new Random();
                
                Circle {
                    transforms: [
                        
                    ]
                    centerX: 0
                    centerY: 0
                    radius: 30
                    fill: Color.rgb(175, 238, 238, 0.6)
                    stroke: Color.SKYBLUE
                }
            }
        ]
    }
}

円の位置は(0, 0)になるようにし、半径は30としました。また、赤字で示したようにtransformsアトリビュートを記述し、要素のないシーケンスを書いておきます。

そして、ここでもコードパレットを使用して、コードを自動生成してしまいましょう。変換を行うのはTransformationsカテゴリの中にあります。まず、Translateを選択して、transformsアトリビュートのシーケンスの中にドロップします。するとスクリプトは次のように変更されます。赤字の部分がコード生成された部分です。

リスト7
Stage {
    title: "Circle Sample"
    scene: Scene {
        width: 200
        height: 200
 
        content: [
            for (i in [0..99]) {
                // 乱数を使って場所や半径を決める
                var rand = new Random();
                
                Circle {
                    transforms: [
                        Translate { 
                            x : 0.0, 
                            y : 0.0 }
                    ]
                    centerX: 0
                    centerY: 0
                    radius: 30
                    fill: Color.rgb(175, 238, 238, 0.6)
                    stroke: Color.SKYBLUE
                }
            }
        ]
    }
}

Translateクラスはxアトリビュートとyアトリビュートで移動量を指定します。

次に、Translateオブジェクトを生成する閉括弧の後にカンマを記入し、その下に空行を挿入します。Circleオブジェクトの部分だけ次に示します。

リスト8
                Circle {
                    transforms: [
                        Translate {
                            x : 0.0,
                            y : 0.0 },
                                                            
                    ]
                    centerX: 0
                    centerY: 0
                    radius: 30
                    fill: Color.rgb(175, 238, 238, 0.6)
                    stroke: Color.SKYBLUE
                }

そして、この空行のところにScaleをドラッグしてドロップします。すると、スクリプトは次のように変更されます。

リスト9
                Circle {
                    transforms: [
                            Translate {
                            x : 0.0,
                        y : 0.0 },
                        Scale { 
                            x : 0.0, 
                            y : 0.0 }
                    ]
                    centerX: 0
                    centerY: 0
                    radius: 30
                    fill: Color.rgb(175, 238, 238, 0.6)
                    stroke: Color.SKYBLUE
                }

赤字の部分が挿入された箇所です。Scaleクラスはx軸方向の拡大率を表すxアトリビュートと、y軸方向の拡大率を表すyアトリビュートからなります。

次に、移動量と縮小率を乱数で定義します。それぞれ、transX、transY、scaleという変数を定義し、乱数で値を決めます。そして、これらの変数をTranslateオブジェクトやScaleオブジェクトのアトリビュートに指定します。最終的なスクリプトは次のようになりました。

リスト10
Stage {
    title: "Circle Sample"
    scene: Scene {
        width: 200
        height: 200
 
        content: [
            for (i in [0..99]) {
                // 乱数を使って場所や半径を決める
                var rand = new Random();
                var transX = rand.nextInt(200);
                var transY = rand.nextInt(200);
                var scale = rand.nextDouble();
 
                Circle {
                    transforms: [
                        Translate {
                            x : transX
                            y : transY
                        },
                        Scale {
                            x : scale
                            y : scale
                        }
                    ]
                    centerX: 0
                    centerY: 0
                    radius: 30
                    fill: Color.rgb(175, 238, 238, 0.6)
                    stroke: Color.SKYBLUE
                }
            }
        ]
    }
}

赤字で示した変数で移動量、縮小率を決めています。では、実際にこのスクリプトを実行してみましょう。実行結果を図25に示しました。

図25 移動、縮小による複数円の描画
図25 移動、縮小による複数円の描画

グラデーションで塗る

先ほどのサンプルでは透明度を設定することで泡っぽく見せていましたが、こんどはボールです。ボールっぽく見せるためにはスポットが当たっているように色を塗ります。これには環状のグラデーションを適用させます。

JavaFX Scriptでは2種類のグラデーションが用意されています。線形のグラデーションを表すjavafx.scene.paint.LinearGradientクラスと環状のグラデーションを表すjavafx.scene.paint.RadialGradientクラスです。ここでは、RadialGradientクラスを使用します。

LinearGradientクラスとRadialGradientクラスは、2色以上の色を使用して色をグラデーションを作成することができます。色の指定にはStopクラスを使用します。

色を指定するには、相対位置で設定するか絶対位置で設定するか選びます。この指定にはproportionalアトリビュートで指定します。proportionalアトリビュートがtrueの場合相対位置、falseの場合絶対位置になります。何も指定しない場合は、デフォルトでtrueに設定されます。相対位置で指定する場合、0から1の値で位置を指定します。つまり、0から1の四角形でシェイプを囲み、その座標系での位置で色を指定することになります。

環状のグラデーションの場合は中心点も指定します。ここでは、中心点を(0.25, 0.25)にし、色の指定を中心点とそこから0.6離れた点にしました。これを図に表したのが図26です。

図26 RadialGradientの指定
図26 RadialGradientの指定

このように設定したRadialGradientオブジェクトをCircleオブジェクトのfillに指定します。スクリプトは次のようになりました。

リスト11
Stage {
    title: "Circle Sample"
    scene: Scene {
        width: 200
        height: 200
 
        content: [
            for (i in [0..99]) {
                // 乱数を使って場所や半径を決める
                var rand = new Random();
                var transX = rand.nextInt(200);
                var transY = rand.nextInt(200);
                var scale = rand.nextDouble();
                
                Circle {
                    transforms: [
                            Translate {
                            x : transX
                            y : transY
                        },
                            Scale {
                            x : scale
                            y : scale
                        }
                    ]
                    centerX: 0
                    centerY: 0
                    radius: 30
 
                    // 環状のグラデーションで色を塗る
                    fill: RadialGradient {
                        centerX: 0.25
                        centerY: 0.25
                        stops: [
                            Stop { 
                                offset: 0.0
                                color: Color.WHITE 
                            },
                            Stop { 
                                offset: 0.6
                                color: Color.SKYBLUE
                            }
                        ]
                    }
                }
            }
        ]
    }
}

赤字の部分がRadialGradientオブジェクトの生成部分です。グラデーションの中心を示すcenterXアトリビュートとcenterYアトリビュートは共に0.25にしてあります。Stopオブジェクトは位置が0.0(つまり中心)のものと、0.6のものがあります。それぞれ、その位置での色は白とスカイブルーです。

では、このスクリプトを実行してみましょう。実行結果を図27に示しました。先ほどの半透明な円と比べると、ずいぶん雰囲気が違いますね。

図27 グラデーションによる塗りつぶし
図27 グラデーションによる塗りつぶし

今回は、円を題材にさまざまな描画を試してみました。円以外にも四角や楕円なども同じように描画することができます。ぜひ、他のシェイプでも試してみてください。

また、文字を描画するjavafx.scene.text.TextクラスもShapeクラスのサブクラスなので、ここで使用したfillアトリビュートやtransformsアトリビュートなどがアトリビュートとして定義されています。したがって、グラデーションで塗ったり、変形させるということも可能です。こちらもぜひ試してみてください。

次回は、if文など前回説明しなかった文法について解説する予定です。

おすすめ記事

記事・ニュース一覧