最終更新日: 2013/9/10
FXMLは、Javaオブジェクト・グラフを構築するためのスクリプト可能なXMLベースのマークアップ言語です。そのようなグラフを手続き型のコードで構築する方法の便利な代替方法であり、JavaFXアプリケーションのユーザー・インタフェースの定義に最適です。これは、XMLドキュメントの階層構造が、JavaFXシーン・グラフの構造と密接に対応しているためです。
このドキュメントでは、FXMLマークアップ言語の概要を示し、これを使用してJavaFXアプリケーションの開発をどのように簡素化できるかについて説明します。
FXMLでは、XML要素は次のいずれかを表します。
クラス・インスタンス、インスタンス・プロパティ、静的プロパティおよびdefineブロックについては、この項で後述します。スクリプトについては、後の項で説明します。
クラス・インスタンスは、FXMLで複数の方法で構築できます。最も一般的には、インスタンス宣言要素を使用します。この場合、単純に名前でクラスの新しいインスタンスが作成されます。クラス・インスタンスを作成するその他の方法には、既存の値の参照、既存の値のコピー、外部FXMLファイルの読込みなどがあります。それぞれの方法については、次に詳しく説明します。
<?import javafx.scene.control.Label?>
このPIでは、javafx.scene.controlパッケージからすべてのクラスが現在のネームスペースにインポートされます。
<?import javafx.scene.control.*?>
<?import javafx.scene.control.Label?> <Label text="Hello, World!"/>
この例で、Labelのtextプロパティは、XML属性を使用して設定されます。プロパティは、ネストされたプロパティ要素を使用して設定することもできます。プロパティ要素については、この項の後半で詳しく説明します。プロパティ属性については、後の項で説明します。
Bean規則に準拠しないクラスも、ビルダーと呼ばれるオブジェクトを使用してFXMLで構築できます。ビルダーについては、後で詳しく説明します。
内部的に、FXMLローダーはcom.sun.javafx.fxml.BeanAdapterのインスタンスを使用して、インスタンス化されたオブジェクトをラップし、そのセッター・メソッドを呼び出します。このprivate (現在)クラスはjava.util.Mapインタフェースを実装し、コール元がBeanプロパティ値をキー/値ペアとして取得および設定できるようにします。
<HashMap foo="123" bar="456"/>
<String fx:value="Hello, World!"/> <Double fx:value="1.0"/> <Boolean fx:value="false"/>
static valueOf(String)メソッドを定義するカスタム・クラスもこの方法で構築できます。
<FXCollections fx:factory="observableArrayList"> <String fx:value="A"/> <String fx:value="B"/> <String fx:value="C"/> </FXCollections>
FXMLにおけるビルダーのサポートは、2つのインタフェースによって提供されます。javafx.util.Builderインタフェースは、実際のオブジェクトを構築するbuild()という名前の単一のメソッドを定義します。
public interface Builder<T> { public T build(); }
javafx.util.BuilderFactoryは、指定された型をインスタンス化できるビルダーを生成します。
public interface BuilderFactory { public Builder<?> getBuilder(Class<?> type); }
デフォルト・ビルダー・ファクトリのJavaFXBuilderFactoryは、javafx.fxmlパッケージで提供されます。このファクトリは、ほとんどの不変JavaFX型を作成および構成できます。たとえば、次のマークアップは、デフォルト・ビルダーを使用して、不変javafx.scene.paint.Colorクラスのインスタンスを作成します。
<Color red="1.0" green="0.0" blue="0.0"/>
要素の開始タグの処理時に作成されるBeanタイプとは異なり、ビルダーによって作成されるオブジェクトは、要素の終了タグに到達するまでインスタンス化されません。これは、要素が完全に処理されるまで、必要なすべての引数が利用できない場合があるためです。たとえば、前の例のColorオブジェクトは、次のように記述することもできます。
<Color> <red>1.0</red> <green>0.0</green> <blue>0.0</blue> </Color>
Colorインスタンスは、3つの色の構成要素がすべて認識されるまで完全には作成されません。
ビルダーによって作成されるオブジェクトのマークアップを処理する場合、Builderインスタンスは値オブジェクトとして処理され、BuilderがMapインタフェースを実装する場合、put()メソッドを使用してビルダーの属性値が設定されます。それ以外の場合、ビルダーはBeanAdapterでラップされ、そのプロパティは標準Beanセッターを介して公開されると想定されます。
<fx:include>タグは、別のファイルで定義されたFXMLマークアップからオブジェクトを作成します。次のように使用されます。
<fx:include source="filename"/>
filenameは、読み込むFXMLファイルの名前です。
たとえば、次のマークアップを考えてみます。
<?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <VBox xmlns:fx="http://javafx.com/fxml"> <children> <fx:include source="my_button.fxml"/> </children> </VBox>
my_button.fxmlに次が含まれるとします。
<?import javafx.scene.control.*?> <Button text="My Button"/>
この場合、生成されるシーン・グラフには、子ノードとして単一のButtonを持つルート・オブジェクトとしてVBoxが含まれます。
fxネームスペース接頭辞が使用されていることに注意してください。これは、FXMLソース・ファイルの内部処理に使用される要素と属性の数を定義する予約済接頭辞です。通常、これはFXMLドキュメントのルート要素で宣言されます。fxネームスペースによって提供されるその他の機能については、以降の項で説明します。
<fx:include>は、読み込まれるコンテンツのローカライズに使用されるリソース・バンドルの名前を指定する属性、およびソース・ファイルのエンコードに使用される文字セットもサポートします。リソース解決については、後の項で説明します。
<fx:include source="filename" resources="resource_file" charset="utf-8"/>
<Button> <minHeight><Double fx:constant="NEGATIVE_INFINITY"/></minHeight> </Button>
たとえば、次のマークアップは、前に定義したmyImageという名前のImageインスタンスをImageViewコントロールのimageプロパティに割り当てます。
<ImageView> <image> <fx:reference source="myImage"/> </image> </ImageView>
属性変数解決演算子を使用して変数を逆参照することもできますが(後で「属性」の項で説明します)、fx:referenceは、通常、コレクションに参照を追加する場合など、参照値を要素として指定する必要がある場合にのみ使用されます。
<ArrayList> <fx:reference source="element1"/> <fx:reference source="element2"/> <fx:reference source="element3"/> </ArrayList>
他のほとんどの場合は、属性を使用する方がより簡単で簡潔です。
現在、このようなコピー・コンストラクタを提供するJavaFXプラットフォーム・クラスは存在しないため、この要素は主にアプリケーション開発者向けに提供されています。これは将来のリリースで変更される可能性があります。
タグ名が小文字で始まる要素は、オブジェクト・プロパティを表します。プロパティ要素は次のいずれかを表します。
たとえば、次のFXMLは、Labelクラスのインスタンスを作成し、ラベルのtextプロパティの値をHello, World!に設定します。
<?import javafx.scene.control.Label?> <Label> <text>Hello, World!</text> </Label>
これにより、結果は、属性を使用してtextプロパティを設定した以前の例と同じになります。
<?import javafx.scene.control.Label?> <Label text="Hello, World!"/>
通常、プロパティ要素は、プロパティ値が単純な文字列ベースの属性値を使用して表すことができない複合型の場合、または値の文字列長が非常に長いため、属性として指定すると読みにくくなる場合に使用されます。
FXMLローダーは、BeanAdapterのcoerce()メソッドを使用して必要な型変換を実行します。このメソッドは、Stringからbooleanまたはintからdoubleなどの基本のプリミティブ型変換を実行でき、StringからClassまたはStringからEnumへの変換も行います。ターゲット型でstatic valueOf()メソッドを定義して、追加の変換を実装できます。
たとえば、javafx.scene.Groupのchildrenプロパティは、グループの子ノードを表す読取り専用リスト・プロパティです。
<?import javafx.scene.*?> <?import javafx.scene.shape.*?> <Group xmlns:fx="http://javafx.com/fxml"> <children> <Rectangle fx:id="rectangle" x="10" y="10" width="320" height="240" fill="#ff0000"/> ... </children> </Group>
<children>要素の各サブ要素は、読み取られるたびにGroup#getChildren()によって返されるリストに追加されます。
javafx.scene.Nodeのpropertiesプロパティは、読取り専用マップ・プロパティの例です。次のマークアップは、Labelインスタンスのfooおよびbarプロパティを、123と456にそれぞれ設定します。
<?import javafx.scene.control.*?> <Button> <properties foo="123" bar="456"/> </Button>
たとえば、javafx.scene.layout.Pane (javafx.scene.layout.VBoxのスーパークラス)では子のデフォルト・プロパティが定義されるため<children>要素は不要で、ローダーによってVBoxのサブ要素がコンテナの子コレクションに自動的に追加されます。
<?import javafx.scene.*?> <?import javafx.scene.shape.*?> <VBox xmlns:fx="http://javafx.com/fxml"> <Button text="Click Me!"/> ... </VBox>
デフォルト・プロパティは、コレクションに限定されません。要素のデフォルト・プロパティがスカラー値を参照する場合、その要素のサブ要素はプロパティの値として設定されます。
たとえば、javafx.scene.control.ScrollPaneではコンテンツのデフォルト・プロパティが定義されるため、コンテンツとしてTextAreaを含むスクロール・ペインを次のように指定できます。
<ScrollPane> <TextArea text="Once upon a time..."/> </ScrollPane>
デフォルト・プロパティを利用すると、FXMLマークアップの冗長度を大幅に低下させることができます。
静的プロパティには、静的プロパティを定義するクラス名の接頭辞が付けられます。たとえば、次のFXMLは、GridPaneのrowIndexおよびcolumnIndexプロパティの静的セッターを呼び出します。
<GridPane> <children> <Label text="My Label"> <GridPane.rowIndex>0</GridPane.rowIndex> <GridPane.columnIndex>0</GridPane.columnIndex> </Label> </children> </TabPane>
これは、Javaでおおむね次のように変換されます。
GridPane gridPane = new GridPane(); Label label = new Label(); label.setText("My Label"); GridPane.setRowIndex(label, 0); GridPane.setColumnIndex(label, 0); gridPane.getChildren().add(label);GridPane#setRowIndex()およびGridPane#setColumnIndex()へのコールは、Labelインスタンスに索引データをアタッチします。GridPaneでは、レイアウト時にこれらを使用して子を適切に配置します。AnchorPane、BorderPane、StackPaneなどの他のコンテナは、同様のプロパティを定義します。
インスタンス・プロパティと同様に、静的プロパティ要素は、通常、プロパティ値を属性値で効率的に表すことができない場合に使用されます。それ以外の場合は、一般に、静的プロパティ属性(後の項で説明します)によってより簡潔で読みやすいマークアップが生成されます。
たとえば、ラジオ・ボタンを使用する場合は、一般的に、ボタンの選択状態を管理するToggleGroupを定義します。このグループはシーン・グラフ自体の一部ではないため、ボタンの親に追加することはできません。定義ブロックを使用すると、ドキュメントの構造全体に影響を与えることなくボタン・グループを作成できます。
<VBox> <fx:define> <ToggleGroup fx:id="myToggleGroup"/> </fx:define> <children> <RadioButton text="A" toggleGroup="$myToggleGroup"/> <RadioButton text="B" toggleGroup="$myToggleGroup"/> <RadioButton text="C" toggleGroup="$myToggleGroup"/> </children> </VBox>
定義ブロック内の要素は、通常、後で要素の値を参照するために使用できるIDが割り当てられます。IDについては、後の項で詳しく説明します。
FXMLで属性は次のいずれかを表します。
それぞれについて、以降の項で詳しく説明します。
<?import javafx.scene.control.*?> <Button text="Click Me!"/>
<Rectangle fx:id="rectangle" x="10" y="10" width="320" height="240" fill="#ff0000"/>
処理時に適用されるプロパティ要素とは異なり、プロパティ属性は、それぞれの要素の終了タグに到達するまで適用されません。これは主に、要素のコンテンツが完全に処理されるまで利用できない情報に属性値が依存するケースを容易にするためです(たとえば、すべてのタブが追加されるまで設定できないTabPaneコントロールの選択された索引など)。
FXMLのプロパティ属性とプロパティ要素間のもう1つの重要な相違点は、属性が、その機能を拡張する多数の解決演算子をサポートしていることです。サポートされている演算子とその説明を次に示します。
たとえば、次のマークアップでは、ImageViewが作成され、現在のFXMLファイルに対する相対パスにあると想定されるmy_image.pngからイメージ・データが移入されます。
<ImageView> <image> <Image url="@my_image.png"/> </image> </ImageView>
Imageは不変オブジェクトであるため、これを作成するにはビルダーが必要です。または、ImageがvalueOf(URL)ファクトリ・メソッドを定義する場合は、イメージ・ビューを次のように移入できます。
<ImageView image="@my_image.png"/>
image属性の値はFXMLローダーによってURLに変換され、次にvalueOf()メソッドを使用してImageに強制変換されます。
URL内の空白値はエンコードする必要があり、たとえば、My Image.pngという名前のファイルを参照するには、FXMLドキュメントに次を含める必要があります。
<Image url="@My%20Image.png"/>
次のようにはなりません。
<Image url="@My Image.png"/>
FXMLでは、ローカリゼーションの目的でロード時にリソース置換を実行できます。java.util.ResourceBundleのインスタンスが提供された場合、FXMLローダーはリソース名のインスタンスをロケール固有の値に置き換えます。リソース名は、次に示すように、%接頭辞によって識別されます。
<Label text="%myText"/>
次のように定義されたリソース・バンドルがローダーに指定されるとします。
myText = This is the text!
この場合、FXMLローダーの出力は、This is the text!というテキストを含むLabelインスタンスになります。
<fx:define> <ToggleGroup fx:id="myToggleGroup"/> </fx:define> ... <RadioButton text="A" toggleGroup="$myToggleGroup"/> <RadioButton text="B" toggleGroup="$myToggleGroup"/> <RadioButton text="C" toggleGroup="$myToggleGroup"/>
<Label text="\$10.00"/>
前述の属性変数は、ロード時に1回解決されます。変数値に対する以降の更新は、値の割当て先のプロパティに自動的に反映されません。多くの場合、これは十分な動作ですが、変数に対する変更がターゲット・プロパティに自動的に伝播されるようにプロパティ値を変数または式にバインドすると便利な場合がよくあります。この目的で、式バインディングを使用できます。
<TextField fx:id="textField"/> <Label text="${textField.text}"/>
ユーザーがテキスト入力を入力すると、ラベルのテキスト・コンテンツが自動的に更新されます。
より複雑な式もサポートされています。サポートされている定数と演算子のリストは次のとおりです。
"string" 'string' | 文字列定数 |
true false | ブール定数 |
null | null値の定数 |
50.0 3e5 42 | 数値定数 |
- (単項演算子) | 数値に適用される、単項マイナス演算子 |
! (単項演算子) | ブールの単項マイナス |
+ - * / % | 数値バイナリ演算子 |
&& || | ブール・バイナリ演算子 |
> >= < <= == != |
比較のバイナリ演算子 両方の引数がComparable型である必要があります |
<GridPane> <children> <Label text="My Label" GridPane.rowIndex="0" GridPane.columnIndex="0"/> </children> </TabPane>
イベント・ハンドラ属性は、ドキュメント要素に動作をアタッチする便利な方法です。setOnEvent()メソッドを定義するクラスにマークアップでイベント・ハンドラを割り当てることができます。
FXMLでは、スクリプト・イベント・ハンドラ、コントローラ・メソッド・イベント・ハンドラおよび式の3つのタイプのイベント・ハンドラ属性がサポートされています。それぞれについて次に説明します。
<?language javascript?> ... <VBox> <children> <Button text="Click Me!" onAction="java.lang.System.out.println('You clicked me!');"/> </children> </VBox>
コントローラ・メソッド・イベント・ハンドラは、ドキュメントのコントローラによって定義されるメソッドです。コントローラは、FXMLドキュメントのデシリアライズされたコンテンツに関連付けられるオブジェクトで、ドキュメントで定義されるオブジェクト(多くの場合ユーザー・インタフェース要素)の動作を調整します。
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml"> <children> <Button text="Click Me!" onAction="#handleButtonAction"/> </children> </VBox>
package com.foo; public class MyController { public void handleButtonAction(ActionEvent event) { System.out.println("You clicked me!"); } }
この場合、ユーザーがボタンを押すと、handleButtonAction()がコールされ、You clicked me!というテキストがコンソールに書き込まれます。
package com.foo; public class MyController { public void handleButtonAction() { System.out.println("You clicked me!"); } }
コントローラについては、後の項で詳しく説明します。
javafx.event.EventHandlerタイプの変数を指す式を式ハンドラとして使用できます。
式ハンドラを使用した前述の例:
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml"> <children> <Button text="Click Me!" onAction="$controller.onActionHandler"/> </children> </VBox>
次のようなフィールドを含むコントローラを使用:
public class MyController { @FXML public EventHandleronActionHandler = new EventHandler<>() { ... } ... }
バインディング式のような他の種類の式は、このコンテキストではサポートされません。
コレクションおよびオブジェクト・プロパティは、setOnEvent()メソッドを使用してリスニングできません。そのため、特殊なハンドラ・メソッドを使用する必要があります。ObservableList、ObservableMapまたはObservableSetは、それぞれListChangeListner.Change、MapChangeListener.ChangeまたはSetChangeListener.Changeパラメータを持つハンドラ・メソッドを指す、特殊なonChange属性を使用します。
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml"> <children onChange="#handleChildrenChange"/> </VBox>ここで、ハンドラ・メソッドは次のようになります。
package com.foo; import javafx.collections.ListChangeListener.Change; public class MyController { public void handleChildrenChange(ListChangeListener.Change c) { System.out.println("Children changed!"); } }
同様に、プロパティ・ハンドラは、ChangeListenerの変更されたメソッドと同じパラメータを持つメソッドです。
changed(ObservableValue<? extends T> observable, T oldValue, T newValue)
親プロパティのハンドラは次のようになります。
public class MyController { public void handleParentChange(ObservableValue value, Parent oldValue, Parent newValue) { System.out.println("Parent changed!"); } }
便宜上、最初のパラメータをObservableValueのサブクラスにできます(例: Property)
プロパティに登録するために、特殊なon<propertyName>Change属性を使用する必要があります。
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml" onParentChange="#handleParentChange"/>
コレクションおよびプロパティは、現在スクリプト・ハンドラをサポートしていません。
たとえば、次のマークアップは、Button要素にアタッチされたアクション・ハンドラによって呼び出されるhandleButtonAction()という関数を定義します。
<?language javascript?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <VBox xmlns:fx="http://javafx.com/fxml"> <fx:script> function handleButtonAction(event) { java.lang.System.out.println('You clicked me!'); } </fx:script> <children> <Button text="Click Me!" onAction="handleButtonAction(event);"/> </children> </VBox>
ボタンをクリックすると、関数を呼び出すイベント・ハンドラがトリガーされ、前述の例と同じ出力が生成されます。
<?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <VBox xmlns:fx="http://javafx.com/fxml"> <fx:script source="example.js" charset="cp1252"/> <children> <Button text="Click Me!" onAction="handleButtonAction(event);"/> </children> </VBox>
function handleButtonAction(event) { java.lang.System.out.println('You clicked me!'); }
多くのテキスト・エディタでは、JVMでサポートされている各種スクリプト言語の構文の強調表示が可能であるため、多くの場合、このようにマークアップからコードを分けることが適切です。これは、ソース・コードとマークアップを読みやすくするためにも役立ちます。
スクリプト・ブロックは、イベント・ハンドラ関数の定義に限定されません。スクリプト・コードは処理時に実行されるため、結果の出力の構造を動的に構成するために使用することもできます。簡単な例として、次のFXMLにはlabelTextという名前の変数を定義するスクリプト・ブロックが含まれています。この変数の値は、Labelインスタンスのテキスト・プロパティを移入するために使用されます。
<fx:script> var myText = "This is the text of my label."; </fx:script> ... <Label text="$myText"/>
警告: JavaFX 8.0では、importClass() javascript関数はサポートされなくなりました。前述の例では完全修飾名を使用するか、nashorn互換スクリプトをロードする必要があります。
load("nashorn:mozilla_compat.js"); importClass(java.lang.System); function handleButtonAction(event) { System.out.println('You clicked me!'); }
単純なイベント・ハンドラをスクリプトでインラインまたは外部ファイルで定義して記述することが便利な場合もありますが、多くの場合、より複雑なアプリケーション・ロジックをコンパイル済のJavaなどの強い型指定の言語で定義することが適切です。前述のように、fx:controller属性を使用すると、コール元はコントローラ・クラスをFXMLドキュメントに関連付けることができます。コントローラは、ドキュメントで定義されたオブジェクト階層の背後にコードを実装するコンパイル済クラスです。
前述のように、コントローラは多くの場合、マークアップで定義されているユーザー・インタフェース要素のイベント・ハンドラを実装するために使用されます。
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml"> <children> <Button text="Click Me!" onAction="#handleButtonAction"/> </children> </VBox>
package com.foo; public class MyController { public void handleButtonAction(ActionEvent event) { System.out.println("You clicked me!"); } }
public void initialize();
たとえば、次のコードは、前述の例で行ったようにイベント・ハンドラ属性を使用するのではなく、コードでボタンにアクション・ハンドラをアタッチするinitialize()メソッドを定義します。ボタン・インスタンス変数は、ドキュメントの読取り時にローダーによって注入されます。結果のアプリケーション動作は同じです。
<VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml"> <children> <Button fx:id="button" text="Click Me!"/> </children> </VBox>
package com.foo; public class MyController implements Initializable { public Button button; @Override public void initialize(URL location, Resources resources) button.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { System.out.println("You clicked me!"); } }); } }
たとえば、前述の例のコントローラは次のように書き換えることができます。
package com.foo; public class MyController { @FXML private void handleButtonAction(ActionEvent event) { System.out.println("You clicked me!"); } }
package com.foo; public class MyController implements Initializable { @FXML private Button button; @FXML protected void initialize() button.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { System.out.println("You clicked me!"); } }); } }
最初の例で、handleButtonAction()は、コントローラのドキュメントで定義されているマークアップで呼び出すことができるように、@FXMLがタグ付けされています。2番目の例で、ボタン・フィールドはローダーが値を設定できるように注釈付けされています。initialize()メソッドは同様に注釈付けされます。
<VBox fx:controller="com.foo.MainController"> <fx:define> <fx:include fx:id="dialog" source="dialog.fxml"/> </fx:define> ... </VBox>
public class MainController extends Controller { @FXML private Window dialog; @FXML private DialogController dialogController; ... }
コントローラのinitialize()メソッドがコールされると、dialogフィールドに"dialog.fxml" includeからロードされたルート要素が含まれ、dialogControllerフィールドにincludeのコントローラが含まれます。その後、たとえば、ダイアログを移入および表示するために、メイン・コントローラは含まれるコントローラ上でメソッドを呼び出すことができます。それ以外では、fx:includeで参照されるファイルのコンテンツは、main_window_content.fxmlから広がるシーン・グラフの一部になるため、fx:includeをfx:defineでラップして、両方のウィンドウのシーン・グラフを切り離す必要があることに留意してください。
FXMLLoaderクラスは、FXMLソース・ファイルを実際にロードして結果のオブジェクト・グラフを返します。たとえば、次のコードは、ロードするクラスに対する相対クラスパス上の場所からFXMLファイルをロードし、com.foo.exampleという名前のリソース・バンドルを使用してローカライズします。ルート要素のタイプはjavafx.scene.layout.Paneのサブクラスであると想定され、ドキュメントはタイプMyControllerのコントローラを定義すると想定されます。
URL location = getClass().getResource("example.fxml"); ResourceBundle resources = ResourceBundle.getBundle("com.foo.example"); FXMLLoader fxmlLoader = new FXMLLoader(location, resources); Pane root = (Pane)fxmlLoader.load(); MyController controller = (MyController)fxmlLoader.getController();
FXMLLoaderの
たとえば、次のマークアップは、TextFieldおよびButtonインスタンスを含む単純なカスタム・コントロールの構造を定義します。ルート・コンテナは、javafx.scene.layout.VBoxのインスタンスとして定義されます。
<?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <fx:root type="javafx.scene.layout.VBox" xmlns:fx="http://javafx.com/fxml"> <TextField fx:id="textField"/> <Button text="Click Me" onAction="#doSomething"/> </fx:root>
前述のように、<fx:root>タグは、以前に定義されたルート要素への参照を作成します。この要素の値を取得するには、FXMLLoaderのgetRoot()メソッドをコールします。
次の例では、CustomControlクラスがVBox(<fx:root>要素で宣言された型)を拡張し、それ自体をそのコンストラクタ内のFXMLドキュメントのルートとコントローラの両方として設定します。ドキュメントがロードされると、CustomControlの内容に前のFXMLドキュメントのコンテンツが移入されます。
package fxml; import java.io.IOException; import javafx.beans.property.StringProperty; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.control.TextField; import javafx.scene.layout.VBox; public class CustomControl extends VBox { @FXML private TextField textField; public CustomControl() { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("custom_control.fxml")); fxmlLoader.setRoot(this); fxmlLoader.setController(this); try { fxmlLoader.load(); } catch (IOException exception) { throw new RuntimeException(exception); } } public String getText() { return textProperty().get(); } public void setText(String value) { textProperty().set(value); } public StringProperty textProperty() { return textField.textProperty(); } @FXML protected void doSomething() { System.out.println("The button was clicked!"); } }
コール元は、コードまたはマークアップでこのコントロールのインスタンスを他のコントロールと同様に使用できるようになりました。例:
HBox hbox = new HBox(); CustomControl customControl = new CustomControl(); customControl.setText("Hello World!"); hbox.getChildren().add(customControl);
<HBox> <CustomControl text="Hello World!"/> </HBox>
Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.