第4回でシェイプを扱いましたが、
第1回でJavaFXはSwingとJava2Dをベースに作られているということを述べました。そのため、
とはいうものの、
ということで、
Swingのコンポーネントを使用する
まず、
まず、
プロジェクトが作成できたら、
空っぽのファイルが作成されたので、
import javafx.stage.Stage;
import javafx.scene.Scene;
Stage {
title: "MyApp"
scene: Scene {
width: 200
height: 200
content: [ ]
}
}
さあ、

ここではButtonをドラッグし、

Buttonをドロップすると、
import javafx.ext.swing.SwingButton;
import javafx.scene.Scene;
import javafx.stage.Stage;
Stage {
title: "MyApp"
scene: Scene {
width: 200
height: 200
content: [
SwingButton {
text: "Button"
action: function() {
}
}
]
}
}
ここからわかることは、
JavaFX ScriptのAPIドキュメントを見るとわかりますが、
それでは、

JavaFXをJava SE 6u10以降のバージョンで動作させると、
それでは、
第3回で触れたシェイプも、
リスト3のコードではwidth、
Stage {
title: "Button Sample"
scene: Scene {
width: 140
height: 100
content: [
SwingButton {
text: "Click!"
width: 100
height: 60
translateX: 20
translateY: 20
font: Font {
size: 24
}
action: function() {
}
}
]
}
}
widthアトリビュートはコンポーネントの幅、

イベント処理を追加する
では、
ここでは、
バインドは変数やアトリビュートを自動的に同期させる機構です。この例ではボタンに表示する文字列を保持する変数を作成し、
// ボタンに表示する文字列
var buttonText = "Click!";
Stage {
title: "Button Sample"
scene: Scene {
width: 280
height: 100
content: [
SwingButton {
// 表示文字列は buttonText にバインドする
text: bind buttonText
width: 240
height: 60
translateX: 20
translateY: 20
font: Font {
size: 24
}
action: function() {
// クリックされたらbuttonTextを更新する
buttonText = "One More Click!"
}
}
]
}
}
変数buttonTextがボタンに表示する文字列です
JavaではActionListenerインターフェースをインプリメントしたクラスを作成して、
これで実行してみましょう。なお、
実行すると、


ここではアクションイベントを変更しましたが、
// ボタンに表示する文字列
var buttonText = "Initial";
Stage {
title: "Button Sample"
scene: Scene {
width: 240
height: 100
content: [
SwingButton {
// 表示文字列は buttonText にバインドする
text: bind buttonText
width: 200
height: 60
translateX: 20
translateY: 20
font: Font {
size: 24
}
onMouseEntered: function(event: MouseEvent) {
buttonText = "Enter"
}
onMouseExited: function(event: MouseEvent) {
buttonText = "Exit"
}
onMousePressed: function(event: MouseEvent) {
buttonText = "Press"
}
onMouseReleased: function(event: MouseEvent) {
buttonText = "Release"
}
}
]
}
}
actionアトリビュートは引数のない関数でしたが、
図7をクリックすると完成したbuttonsample.

レイアウト
今までのサンプルのように、
レイアウトも現状のJavaFX Scriptでは弱いところです。インタープリタ版ではJavaのGroupLayoutクラスに対応するレイアウトマネージャも提供されていたのですが、
この2つのクラスはその名の通り、

このレイアウトはリスト6のようなコードで実現できます。
VBox {
content: [
HBox {
content: [
SwingTextField { ... },
SwingButton { ... }
]
},
SwingLabel { ... }
]
}
Javaではコンポーネントをレイアウトマネージャに登録するのに何度もaddメソッドをコールしなければいけなかったのですが、
では、
ではsayhello.
var who = "World";
var label = "Hello, World!";
Stage {
scene: Scene {
content: [
SwingTextField {
text: bind who with inverse
},
SwingButton {
action: function() {
label = "Hello, {who}!"
}
},
SwingLabel {
text: bind label
}
]
}
}
テキストフィールドに表示している文字列は変数whoにバインドしてあります。しかし、
そして、
実行結果を図9に示します。この図もアプレットページへのリンクになっています。


ラベルに表示する文字を、
var who = "World";
Stage {
scene: Scene {
content: [
SwingTextField {
text: bind who with inverse
},
SwingButton {
action: function() {
// label = "Hello, {who}!"
}
},
SwingLabel {
text: bind "Hello, {who}!"
}
]
}
}
しかし、
念のため、
import javafx.ext.swing.SwingButton;
import javafx.ext.swing.SwingLabel;
import javafx.ext.swing.SwingTextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.stage.Stage;
var who = "World";
var label = "Hello, World!";
Stage {
title: "Say Hello to..."
scene: Scene {
width: 220
height: 100
content: [
VBox {
translateX: 10
translateY: 10
spacing: 10
content: [
HBox {
spacing: 10
content: [
SwingTextField {
columns: 10
text: bind who with inverse
editable: true
},
SwingButton {
text: "Update"
action: function() {
label = "Hello, {who}!"
}
}
]
},
SwingLabel {
font: Font {
size: 24
}
width:200
text: bind label
}
]
}
]
}
}
他のノードとSwingコンポーネントを組み合わせる
今までのサンプルで、
答えは、
SwingコンポーネントもNodeクラスのサブクラスですから、
図10に示したようにイメージの透明度をスライダで変更して、

では、
アプリケーションの全体を作る前に、
ImageView {
image: Image {
url: "{__DIR__}/myPicture.png"
}
}
このコードを見ると、
同じような名前のImageViewクラスとImageクラスですが、
ImageクラスのurlアトリビュートはイメージをロードするURLを表しています。赤字で示した__
ここでは、

では、
// スライダの値
var sliderValue = 0;
Stage {
title: "Slide Images"
scene: Scene {
width: 300
height: 500
content: [
SwingSlider {
translateX: 20
translateY: 15
width: 260
minimum: 0
maximum: 100
value: bind sliderValue with inverse
vertical: false
},
// 2 枚のイメージで透明度を変化させる
ImageView {
x: 0
y: 50
opacity: bind sliderValue / 100.0
image: Image {
url: "{__DIR__}herme.jpg"
}
},
ImageView {
x: 0
y: 50
opacity: bind 1.0 - sliderValue / 100.0
image: Image {
url: "{__DIR__}aoki.jpg"
}
}
]
}
}
スライダを動かしたときに変数sliderValueも同時に更新されるように、
青字で示したように、
図12にslideimagesの実行結果を示します。イメージが重なっていることがわかるはずです。また、

置換トリガを使う
もう1つ同じようなイメージの切り替えを行ってみましょう。こんどはイメージを移動させて、
重なったイメージを同時に左右に移動させ、

しかし、
ここでは、
y = -0.
もう一方のイメージは反対方向に移動するので、

では、
とりあえず、
// スライダの値にバインドした変数
var sliderValue = 0;
// スライダの値に応じた移動量
var transX = bind sliderValue * (6.0 - 3.0 * sliderValue / 50.0);
Stage {
title: "Slide Images"
scene: Scene {
width: 300
height: 500
content: [
SwingSlider {
translateX: 20
translateY: 15
width: 260
minimum: 0
maximum: 100
value: bind sliderValue with inverse
vertical: false
},
ImageView {
x: 0
y: 50
translateX: bind transX
image: Image {
url: "{__DIR__}herme.jpg"
}
},
ImageView {
x: 0
y: 50
translateX: bind -transX
image: Image {
url: "{__DIR__}aoki.jpg"
}
}
]
}
}
赤字で示した式が放物線の数式に対応します。それぞれのイメージのtranslateXアトリビュートは青字で示したように、
この段階で一度実行させてみましょう。イメージは移動するものの、

では、
コンポーネントの表示順はSceneオブジェクトのcontentアトリビュートの要素順によって決まります。contentアトリビュートはシーケンスであり、
現在のcontentアトリビュートは以下のようになっています。
content: [スライダ, チョコケーキ, イチゴケーキ]
つまり、
content: [スライダ, イチゴケーキ, チョコケーキ]
順番を入れ替えるにはシーケンスに対するreverse演算子を適用すればいいのですが、
var images = [チョコケーキ, イチゴケーキ]
content: [スライダ, images]
if (sliderValue == 50) {
images = reverse images;
}
ここで思い出していただきたいのが、
順番を入れ替えるのはimagesだけなので、
問題は上記のコードのif文をどこに書くかということです。ここで使えるのが、
置換トリガーを使用すれば、
// イメージのシーケンス
// 未定義でエラーにならないよう、先に定義だけ行う
var images: ImageView[] = [];
// スライダの値にバインドした変数
// スライダの位置が半分に来た時にイメージの並び順を変更する
var sliderValue = 0 on replace {
if (sliderValue == 50) {
images = reverse images;
}
};
// スライダの値に応じた移動量
var transX = bind sliderValue * (6.0 - 6.0 * sliderValue / 100.0);
// 2 枚のイメージ
images = [
ImageView {
x: 0
y: 50
translateX: bind transX
image: Image {
url: "{__DIR__}herme.jpg"
}
},
ImageView {
x: 0
y: 50
translateX: bind -transX
image: Image {
url: "{__DIR__}aoki.jpg"
}
}
];
Stage {
title: "Slide Images"
scene: Scene {
width: 300
height: 500
// バインドするのは images の変更に同期するため
content: bind [
SwingSlider {
translateX: 20
translateY: 15
width: 260
minimum: 0
maximum: 100
value: bind sliderValue with inverse
vertical: false
},
images
]
}
}
赤字で示したように、
変数imagesは変数sliderValueの定義より前に初期化もできればいいのですが、
また、
では、

Swingコンポーネントはノード
最後にちょっとしたおまけ的なものを紹介しましょう。Swingコンポーネントはシェイプなどのノードと同等に扱えると何度も書いてきました。では、
// スライダの値
var sliderValue = 0;
Stage {
title: "Rotate Field"
scene: Scene {
width: 300
height: 250
content: [
SwingSlider {
translateX: 20
translateY: 15
width: 260
minimum: -180
maximum: 180
value: bind sliderValue with inverse
vertical: false
},
SwingTextField {
translateX: 50
translateY: 120
width: 200
height: 50
// テキストフィールドを回転させる
rotate: bind sliderValue
columns: 10
font: Font {
size: 24
}
text: "TextField"
editable: true
}
]
}
}
このスクリプトを実行すると、
このようなことができると、

今回は、
次回は、