FrameとStageによるグラフィック表示
1.0では、SwingFrameの他に、グラフィック表示を行うFrameクラスを使って表示を行うこともできます。こちらのクラスを使った形に書き直してみましょう。
package fxsample;
import javafx.application.*;
import javafx.scene.geometry.Circle;
import javafx.scene.paint.Color;
Frame {
title: "Title"
width: 200
height: 200
visible: true
stage: Stage {
content: Circle {
centerX: 100, centerY: 80
radius: 50
fill: Color.RED
}
}
}
Frameは、javafx.applicationパッケージに用意されています。このクラスには「stage」というアトリビュートがあり、ここにjavafx.application.Stageクラスのインスタンスとして表示する内容を用意します。
Stageは、Canvasにシェイプを組み込んでグラフィックを作成するのと同じ感覚でグラフィックを用意していくことができます。contentアトリビュートに、シェイプ関係のオブジェクトを配列として用意すれば良いのです。
SwingのGUIを必要とせず、単にグラフィックだけを表示するのであれば、Frameを使った方がよりシンプルに表示を作成することができるでしょう。ただし、FrameのcontentではSwingコンポーネントは組み込むことができません。
アニメーションについて
JavaFX Scriptでは、図形などのアトリビュートの値を連続して変更することで、簡易アニメーションを行うことができます。一例として、円をクリックすると、円が小さな点からゆっくりと大きな円に変化していくアニメーションを、0.7のスクリプトで作ってみましょう。
import javafx.ui.*;
import javafx.ui.canvas.*;
class AttrModel {
attribute radius: Integer;
}
var model = AttrModel {
radius: 50
};
Frame {
title:"タイトル"
width:200
height:200
visible:true
content: Canvas {
content: [
Circle {
cx: 100 cy: 80
radius: bind model.radius
fill: red
onMouseClicked: operation(e){
model.radius = [0..50] dur 5000;
}
}
]
}
}
0.7では、クラスのアトリビュートを扱う場合には、モデルクラスを定義してアトリビュートをバインドしました。そして、モデルクラスのアトリビュートの値を操作することで、バインドされたオブジェクトのアトリビュートを変更していたわけです。
ここでは、CircleのonMouseClickedにoperationを設定し、モデルクラスAttrModelのradiusの値を操作しています。[0..50] dur 5000とすることで、配列の全要素を5000ミリ秒かけて設定していくようにしてあります。これにより、5秒かけてCircleのradius(直径)がゼロから50まで変化し、擬似アニメーション表示するわけです。
TimelineとKeyFrameによるアニメーション
では、1.0では、アニメーションはどのように行うのでしょうか。1.0では、先の「durを使って配列の要素を一定時間内に設定していく」という機能がありません。ではどうするのかと言うと、「Timeline」という、アニメーションのための時間軸の管理をするクラスを利用します。この中に、「KeyFrame」というアニメーションのフレームに相当するクラスを用意し、これを使ってアニメーションを行ってゆくのです。
package fxsample;
import java.lang.System;
import javafx.application.*;
import javafx.scene.geometry.Circle;
import javafx.scene.paint.Color;
import javafx.animation.*;
var radiusNum = 50;
var timeline = Timeline {
keyFrames : [
for(i in [0..50]){
KeyFrame {
time: 100ms * i
values: radiusNum => i
}
}
]
}
Frame {
title: "Title"
width: 200
height: 200
visible: true
closeAction: function(){
System.exit(0);
}
stage: Stage {
content: [
Circle {
centerX: 100 centerY: 80
radius: bind radiusNum
fill: Color.RED
onMouseClicked: function(e){
timeline.start();
}
}
]
}
}
ここでは、最初にTimelineクラスを用意しています。このクラスには「keyFrames」というアトリビュートが用意されており、ここにキーフレームとなるKeyFrameインスタンスを配列として設定することで、そこに設定したフレーム情報を順に設定してアニメーションを実行していきます。
ここでは、for(i in [0..50])という繰り返し構文の中で、KeyFrameを用意しています。ちょっと不思議な感じがしますが、配列の[]内にforが置かれていますね。1.0では、こうした書き方も可能です。これにより、配列内に繰り返しを使って多数のKeyFrameインスタンスを設定しているのです。
KeyFrameには、「time」と「values」というアトリビュートを用意しています。timeは、そのキーフレームが実行される経過時間を示します。ここでは、100ms * iという値が設定されていますね?「100ms」というのは、JavaFX Scriptに新たに加わった値のタイプ「Duration」の値です。Durationは、時間を示す値です。これは数値の後に時間の単位をつけて記述します。ここで使っている「100ms」というのは「100ミリ秒」を示す値です。これにiをかけて、それぞれのキーフレームのtimeを100ミリ秒の倍数で設定していたわけです。
「values」は、キーフレームで設定される値に関するアトリビュートです。ここでは「radiusNum => i」という値が設定されていますね。これにより、radiusNumにiの値が設定されます。valuesでは、この=>を使うことで、それぞれのキーフレームごとに特定の値を設定することができます。
アニメーションの開始は、CircleのonMouseClickedに用意したfunctionで行っています。ここでは、Timelineインスタンスの「start」を呼び出していますね。これで、このTimelineのkeyFrameに用意されたフレームを順に実行していき、アニメーションが行われるというわけです。
また、ちょっと見落としてしまいがちですが、ここではごく普通の変数にアトリビュートをバインドしていますね。0.7では、ただの変数にバインドすることはできませんでした。わざわざ専用のモデルクラスを定義し、そのアトリビュートにバインドをしていました。が、1.0では、このように変数をバインドに利用することができます。1つ2つの値をバインドするのにいちいちクラスを定義するのは面倒ですから、ちょっとした値の操作ならこの方が簡単で便利です。

