はじめてのJavaFX
コンテンツ:
はじめに
ただJavaFXのソースコードを眺めているだけではJavaFXを理解することはできません。そこで簡単なJavaFXアプリケーションを作りながらJavaFXについて学びます。
ここでは電卓を作ることを目標にします。電卓を作るために必要なテキストフィールドであったりボタン、ボタンイベント、JavaFXの特徴でもあるトリガーについて紹介します。それでは順番にJavaFXアプリケーションを作っていきましょう!
JavaFXの開発環境を整える
まず、新規プロジェクトからJavaのプロジェクトを作ります。このときプロジェクトの名前などは任意で構いません。又、特に設定をする必要もありません。
次にこのプロジェクトにJavaFXのファイルを追加します。さきほど作ったプロジェクト名の上で右クリックをして「新規」→「その他」をクリックします。そしてその中にあるJavaFX Fileを選択して次へ手順を進めれば完了です。
コンパイル・実行の際は、プログラムの引数にJavaFXのファイル名(xxx.fx)を指定する必要があります。
「構成及び実行」を開いて「JavaFX Application」をダブルクリックします。このときに引数を指定します。例えばHelloWorld.fxというファイルをコンパイル・実行したい場合は以下のような設定になります。
JavaFXプログラミング
Hello World
まずは簡単な「Hello,World」アプリケーションを作ってみましょう。
import javafx.ui.*;
[[Frame]]{
title : "はじめてのJavaFX"
width : 200
height : 50
content : Label{
text : "Hello,World"
}
visible : true
}
実行例:
テキストフィールドの追加
電卓を作る上でテキストフィールドは必要になってきます。さきほどのアプリケーションをテキストフィールドを使って表現してみましょう。
import javafx.ui.*;
Frame{
title : "はじめてのJavaFX"
width : 200
height : 50
content : TextField{
editable : false
value : "Hello,World"
}
visible : true
}
実行例:
これはさきほどのLabelをTextFieldに置き換えただけですね。ちなみに上記の例でのテキストフィールドはユーザが編集を加えることができません。
マルチコンポーネントの利用
電卓にはボタンが必要です、そのためにマルチコンポーネントを追加していきましょう。一般的にGUIの実装では、レイアウトマネージャーを用いてGUIの実装を行います。ここでは単純な例として、シンプルなレイアウトであるFlowLayoutを取り上げます。
JavaFXにはレイアウトに関する便利なクラスが用意されています。例えばFlowLayoutの場合、FlowPanelsというクラスが用意されています。このようにJavaFXではレイアウトに関するクラスは「xxxPanel」という名前規則を持っています。
import javafx.ui.*;
Frame{
title : "はじめてのJavaFX"
width : 200
height :100
content : FlowPanel{ <--*1
content : [
TextField {
editable : false
value : "Hello,World"
width : 100
},
Button{
text : "a"
},
Button{
text : "b"
},
Button{
text : "Clear"
} <--*2
]
} <--*1
visible : true
}
実行例:
ここでは複数のコンポーネントを配列を用いて表現しています。配列は、Java同様「[」と「]」で表され、配列の要素は,(カンマ)で区切ることで増やすことができます。また最後の要素にカンマを書くこともできます(
*2のところにカンマを書くことができる)。
このサンプルではFlowPanelのcontentに複数のコンポーネントを配置していますが、Frameのcontentにも複数のコンポーネントを配列を用いて表現することができます。しかし、同じ方法ではうまくいきません。まずは*1のところをコメントアウトしてみます。単純にこれでFrameのcontentに複数のコンポーネントを配置したことになりました。これを実行してみましょう。
そうすると想像した結果とは異なったものが出てきたはずです。これはすべてのコンポーネントがFrameのBorderLayout.CENTERに従って重なりあってしまうからです。
クリック時のイベント処理
ボタンをクリックしたらなんらかの動作が起こるようにしたいものです。
これを実現するにはボタンにActionListenersのようなものを加える必要があります。
これから先はボタンの動作などの設定なので、GUIの変化がありません。つまり実行例を載せれません。ちょっと味気ないですが我慢して下さいね:D。
また期待した動きをしているかどうかは、System.out.printlnでコンソールに出力される結果を見るか、テキストフィールドの値の変化で確かめてください。
import javafx.ui.*;
import java.lang.System; <--*1
var win = Frame{
title : "はじめてのJavaFX"
width : 200
height :100
content : FlowPanel{
content : [
TextField {
editable : false
value : "Hello,World"
width : 100
},
Button{
text : "a"
action : operation(){
System.out.println("'a' clicked");
}
},
Button{
text : "b"
action : operation(){
System.out.println("'b' clicked");
}
},
Button{
text : "Clear"
action : operation(){
System.out.println("'c' clicked");
}
}
]
}
visible : true
};
ボタンをクリックしたときのイベント処理は説明する必要がないくらい簡単ですね。クリック時の処理をoperation()の中に書くだけです。しかし、クリックしたときにただコンソールに文字を出力するだけでは電卓も作れません。ここで学んだことだけではまだそれを作ることはできません。
注意することは1つインポートするものが増えたことです(*1)。Java同様にほぼすべてのクラスをインポートする場合はjava.lang.*と表記することもできます。
Bindingの実装
JavaFXでは、開発者が自由に新しいクラスを定義したり変数を定義したりすることができます。さきほどの例でも"var win = Frame{..."と変数を使っていました。このことは柔軟なコーディングの助けとなるだけではなく、GUIの実装において、デザインと処理を分離しやすくなります。
Bindingとは自分で定義したデータモデルを自身で利用するための手続きです。これを利用することで変数のいくつかを他の要素に依存させることもできます。例えば、テキストフィールドの値を他の値に依存させることができるのです。ボタンをクリックするとテキストフィールドの値が変化するといった動作もこれを利用します。
import javafx.ui.*;
import java.lang.System;
class TextValue{
attribute value : String;
operation clear(); <--*1
}
operation TextValue.clear(){ <--*1
value = "";
}
var model = TextValue{ <--*2
value : "Hello,Model"
};
var win = Frame{
title : "はじめてのJavaFX"
width : 200
height :100
content : FlowPanel{
content : [
TextField {
editable : false
value : bind model.value <--*3
width : 100
},
Button{
text : "a"
action : operation(){
model.value = model.value.concat("a"); <--*4
}
},
Button{
text : "b"
action : operation(){
model.value = model.value.concat("b"); <--*4
}
},
Button{
text : "Clear"
action : operation(){
model.clear(); <--*5
}
}
]
}
visible : true
};
このプログラムには3つの新しい要素が加わっています。
それは、クラスの宣言、メソッドの宣言と変数の宣言です。クラスの宣言ではオブジェクト(attributes)とメソッド(operations)を定義しています。
まず妙に感じるのは*1の部分でしょう。メソッドの宣言部分ではそのメソッドがなんであるかを定義していないからです。そのメソッドがなんであるか、具体的に宣言しているのは「operation TextValue.clear(){...」のところです。
変数の宣言(*2を参照)では新しくTextValueのインスタンスを作り、変数valueの値を"Hello,Model"としています。
テキストフィールドのvalueの値は(*3を参照)前の例とは少し異なっています。テキストフィールドの値を宣言するとき初期値に特定の値を入れてしまいがちですが、model.valueの値を参照したほうがより良いと言えます(直接"Hello,Model"とするのではなく、"Hello,Model"と書かれた値を参照したほうが良い)。
このことは"bind"を使っていることと深く関係しています。ここでbindを用いると、model.valueの値が変化したとき、すぐにその変化をテキストフィールドに反映させることができます。また、Bindingは双方向であることに注意しましょう。もしテキストフィールドが編集可能であったとき、テキストフィールドの値の変化をmodel.valueへ反映させることもできます。
*4のところではaボタンとbボタンを定義し、これらボタンをクリックするとmodel.valueの後ろへ1文字追加('a'もしくは'b')する処理になっています。ここで注意することは文字列の連結です。Javaでは文字列の連結に「+」を使いますが、JavaFXではそれが使えません。
くわしくはこちらを参照して下さい。
最後にClearボタンについてですが(*5を参照),さきほどのaボタンやbボタンと基本的なことは同じです。model.valueの文字列を消去する動作を加えるのに、直接「model.value = ""」と書くこともできますが、今回はメソッドの働きを確認したいので、「model.clear()」を用いています。
トリガーの追加
まだこのプログラムでは1つ見逃していることがあります。
テキストフィールドの値はいつでも変化させることができますが、その値の変化を知ることはできません。これを解決するには、bind命令を少し書き換えるだけでは実装することはできません。
そこでトリガーという機能の紹介に移りたいと思います、これはJavaFXの特徴ともいうべき機能です。これにより定義したattributeが変化したときなんらかの動作を加えることができます。ここでは単純なトリガーの例を示しますが、トリガーはもっと奥深い機能であること忘れないで下さい。
import javafx.ui.*;
import java.lang.System;
class TextValue{
attribute value : String;
operation clear();
}
operation TextValue.clear(){
value = "";
}
var model = TextValue{
value : "Hello,Model"
};
trigger on TextValue.value[oldValue] = newValue{ <--*1
System.out.println("old:".concat(oldValue).concat("; new:").concat(newValue));
}
var win = Frame{
title : "はじめてのJavaFX"
width : 200
height :100
content : FlowPanel{
content : [
TextField {
editable : false
value : bind model.value
width : 100
},
Button{
text : "a"
action : operation(){
model.value = model.value.concat("a");
}
},
Button{
text : "b"
action : operation(){
model.value = model.value.concat("b");
}
},
Button{
text : "Clear"
action : operation(){
model.value = "";
}
}
]
}
visible : true
};
ここで変更が加えられたのは*1のところだけです。ここでのトリガーの例はまったく無意味な処理であり、この中は簡単に書き換えることができます。
まずはじめのTextValue.valueの部分でトリガーを付加する場所を示しています。次にあるoldValueでは変化する前の古い値を示しています。そして最後にあるnewvValueでは変化した後の新しい値を示しています。oldValueは任意ですので、変化する前の古い値が必要なければこれを省略することもできます。
本文章はここまです。原文にはSwingのコードも掲載されているので、そちらを参照してみるのもいいかもしれません。
&trackback()
最終更新:2007年06月11日 06:54