サーチ…


構文

FXMLの例

ボタンとラベルノードを含むAnchorPane概要を示す簡単なFXMLドキュメント:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" 
        fx:controller="com.example.FXMLDocumentController">
    <children>
        <Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
        <Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
    </children>
</AnchorPane>

このFXMLファイルの例は、コントローラクラスに関連付けられています。この場合のFXMLとコントローラクラスの関連付けは、クラス名をFXMLのルート要素のfx:controller属性の値として指定することによって行われます。fx fx:controller="com.example.FXMLDocumentController"コントローラクラスを使用すると、FXMLファイルで定義されているUI要素のユーザーアクションに応じて、Javaコードを実行できます。

package com.example ;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;

public class FXMLDocumentController {
    
    @FXML
    private Label label;
    
    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        label.setText("Hello World!");
    }
    
    @Override
    public void initialize(URL url, ResourceBundle resources) {
        // Initialization code can go here. 
        // The parameters url and resources can be omitted if they are not needed
    }    
    
}

FXMLLoaderを使用してFXMLファイルをロードすることができます:

public class MyApp extends Application {

    @Override
    public void start(Stage stage) throws Exception {

        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("FXMLDocument.fxml"));
        Parent root = loader.load();
        
        Scene scene = new Scene(root);
        
        stage.setScene(scene);
        stage.show();
    }

}

loadメソッドはいくつかのアクションを実行し、発生する順序を理解すると便利です。この単純な例では、

  1. FXMLLoaderは、FXMLファイルを読み込んで解析します。ファイルに定義されている要素に対応するオブジェクトを作成し、定義されているfx:id属性を記録します。

  2. FXMLファイルのルート要素はfx:controller属性を定義しているため、 FXMLLoaderは指定するクラスの新しいインスタンスを作成します。デフォルトでは、これは指定されたクラスで引数のないコンストラクタを呼び出すことによって行われます。

  3. フィールド名が一致し、 public (推奨されない)または注釈付き@FXML (推奨)のいずれかであるフィールドをコントローラーに持つfx:id属性の要素は、対応するフィールドに「注入」されます。この例ではそう、そこにあるので、 LabelとFXMLファイル内fx:id="label"として定義され、コントローラ内とフィールドが

    @FXML
    private Label label ;
    

    labelフィールドは、 FXMLLoaderによって作成されたLabelインスタンスで初期化されます。

  4. イベントハンドラは、 onXXX="#..."プロパティが定義されたFXMLファイルの要素に登録されます。これらのイベントハンドラは、コントローラクラス内の指定されたメソッドを呼び出します。この例では、 ButtononAction="#handleButtonAction"があり、コントローラはメソッドを定義しているため

    @FXML
    private void handleButtonAction(ActionEvent event) { ... }
    

    ユーザーがボタンを押すなどのアクションがボタンで発生すると、このメソッドが呼び出されます。このメソッドはvoid戻り型でなければならず、イベント型(この例ではActionEventに一致するパラメータを定義するか、またはパラメータを定義することができません。

  5. 最後に、コントローラクラスがinitializeメソッドを定義している場合、このメソッドが呼び出されます。これは@FXMLフィールドが挿入された後に発生するので、このメソッドで安全にアクセスでき、FXMLファイルの要素に対応するインスタンスで初期化されます。 initialize()メソッドは、パラメータを取らないか、 URLResourceBundleとることができURL 。後者の場合には、これらのパラメータは、によって移入されるURL FXMLファイルの場所を表す、および任意ResourceBundle上に設定FXMLLoader介しloader.setResources(...)これらのいずれかが設定されていない場合、 nullなる可能性がありnull

ネストされたコントローラ

単一のコントローラを使用して、単一のFXMLにUI全体を作成する必要はありません。

<fx:include>タグを使用して、1つのfxmlファイルを別のファイルに含めることができます。インクルードされたfxmlのコントローラは、 FXMLLoaderによって作成された他のオブジェクトと同様に、インクルードファイルのコントローラに注入できます。

これは、 fx:id属性を<fx:include>要素に追加することによって行われます。このようにして、インクルードされたfxmlのコントローラは、名前<fx:id value>Controllerフィールドに注入され<fx:id value>Controller

例:

fx:id値注射のフィールド名
foo fooController
答え42 答え42コントローラ
xYz xYzController

サンプルfxmls

カウンタ

これはTextノードを持つStackPaneを含むfxmlです。このfxmlファイルのコントローラは、現在のカウンタ値の取得とカウンタのインクリメントを許可します。

counter.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>

<StackPane prefHeight="200" prefWidth="200" xmlns:fx="http://javafx.com/fxml/1" fx:controller="counter.CounterController">
    <children>
        <Text fx:id="counter" />
    </children>
</StackPane>

CounterController

package counter;

import javafx.fxml.FXML;
import javafx.scene.text.Text;

public class CounterController {
    @FXML
    private Text counter;

    private int value = 0;
    
    public void initialize() {
        counter.setText(Integer.toString(value));
    }
    
    public void increment() {
        value++;
        counter.setText(Integer.toString(value));
    }
    
    public int getValue() {
        return value;
    }
    
}

fxmlを含む

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<BorderPane prefHeight="500" prefWidth="500" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="counter.OuterController">
    <left>
        <Button BorderPane.alignment="CENTER" text="increment" onAction="#increment" />
    </left>
    <center>
        <!-- content from counter.fxml included here -->
        <fx:include fx:id="count" source="counter.fxml" />
    </center>
</BorderPane>

OuterController

インクルードされたfxmlのコントローラーがこのコントローラーに注入されます。ここでは、 Button onActionイベントのハンドラを使用してカウンタをインクリメントします。

package counter;

import javafx.fxml.FXML;

public class OuterController {

    // controller of counter.fxml injected here
    @FXML
    private CounterController countController;

    public void initialize() {
        // controller available in initialize method
        System.out.println("Current value: " + countController.getValue());
    }

    @FXML
    private void increment() {
        countController.increment();
    }

}

コードがouter.fxmlと同じパッケージ内のクラスから呼び出されたと仮定すると、fxmlsは次のようにロードできます。

Parent parent = FXMLLoader.load(getClass().getResource("outer.fxml"));

ブロックを定義する

場合によっては、fxml内の通常のオブジェクト構造の外部で要素を作成する必要があることがあります。

これはDefine Blocks有効になる場所です:

<fx:define>要素内の内容は、親要素用に作成されたオブジェクトには追加されません。

<fx:define>すべての子要素には、 fx:id属性が必要です。

この方法で作成されたオブジェクトは、 <fx:reference>要素を使用するか、または式バインディングを使用して後で参照できます。

<fx:reference>要素が持つ任意の要素を参照するために使用することができるfx:id前処理された属性<fx:reference>と同じ値を使用して要素が処理されfx:idで参照される要素の属性<fx:reference>要素のsource属性。

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>


<VBox xmlns:fx="http://javafx.com/fxml/1" prefHeight="300.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8">
    <children>
        <fx:define>
            <String fx:value="My radio group" fx:id="text" />
        </fx:define>
        <Text>
            <text>
                <!-- reference text defined above using fx:reference -->
                <fx:reference source="text"/>
            </text>
        </Text>
        <RadioButton text="Radio 1">
            <toggleGroup>
                <ToggleGroup fx:id="group" />
            </toggleGroup>
        </RadioButton>
        <RadioButton text="Radio 2">
            <toggleGroup>
                <!-- reference ToggleGroup created for last RadioButton -->
                <fx:reference source="group"/>
            </toggleGroup>
        </RadioButton>
        <RadioButton text="Radio 3" toggleGroup="$group" />
        
        <!-- reference text defined above using expression binding -->
        <Text text="$text" />
    </children>
</VBox>

FXMLにデータを渡す - 既存のコントローラにアクセスする

問題:一部のデータは、fxmlからロードされたシーンに渡す必要があります。

溶液

fx:controller属性を使用してコントローラを指定し、 FXMLLoaderロードに使用されるFXMLLoaderインスタンスからロードプロセス中に作成されたコントローラインスタンスを取得します。

データをコントローラインスタンスに渡し、それらのメソッドでデータを処理するメソッドを追加します。

FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>

<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="valuepassing.TestController">
    <children>
        <Text fx:id="target" />
    </children>
</VBox>

コントローラ

package valuepassing;

import javafx.fxml.FXML;
import javafx.scene.text.Text;

public class TestController {

    @FXML
    private Text target;

    public void setData(String data) {
        target.setText(data);
    }

}

fxmlのロードに使用されるコード

String data = "Hello World!";

FXMLLoader loader = new FXMLLoader(getClass().getResource("test.fxml"));
Parent root = loader.load();
TestController controller = loader.<TestController>getController();
controller.setData(data);

FXMLへのデータの受け渡し - コントローラインスタンスの指定

問題:一部のデータは、fxmlからロードされたシーンに渡す必要があります。

溶液

後でfxmlをロードするために使用するFXMLLoaderインスタンスを使用してコントローラを設定します。

fxmlをロードする前に、コントローラに関連するデータが格納されていることを確認してください。

注意:この場合、fxmlファイルにはfx:controller属性を含めないでください。

FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>

<VBox xmlns:fx="http://javafx.com/fxml/1">
    <children>
        <Text fx:id="target" />
    </children>
</VBox>

コントローラ

import javafx.fxml.FXML;
import javafx.scene.text.Text;

public class TestController {

    private final String data;

    public TestController(String data) {
        this.data = data;
    }
    
    @FXML
    private Text target;
    
    public void initialize() {
        // handle data once the fields are injected
        target.setText(data);
    }

}

fxmlのロードに使用されるコード

String data = "Hello World!";

FXMLLoader loader = new FXMLLoader(getClass().getResource("test.fxml"));

TestController controller = new TestController(data);
loader.setController(controller);

Parent root = loader.load();

パラメータをFXMLに渡す - controllerFactoryを使用する

問題:一部のデータは、fxmlからロードされたシーンに渡す必要があります。

溶液

コントローラの作成を担当するコントローラファクトリを指定します。ファクトリで作成されたコントローラインスタンスにデータを渡します。

FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>

<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="valuepassing.TestController">
    <children>
        <Text fx:id="target" />
    </children>
</VBox>

コントローラ

package valuepassing;

import javafx.fxml.FXML;
import javafx.scene.text.Text;

public class TestController {

    private final String data;

    public TestController(String data) {
        this.data = data;
    }
    
    @FXML
    private Text target;
    
    public void initialize() {
        // handle data once the fields are injected
        target.setText(data);
    }

}

fxmlのロードに使用されるコード

文字列データ= "Hello World!";

Map<Class, Callable<?>> creators = new HashMap<>();
creators.put(TestController.class, new Callable<TestController>() {

    @Override
    public TestController call() throws Exception {
        return new TestController(data);
    }

});

FXMLLoader loader = new FXMLLoader(getClass().getResource("test.fxml"));

loader.setControllerFactory(new Callback<Class<?>, Object>() {

    @Override
    public Object call(Class<?> param) {
        Callable<?> callable = creators.get(param);
        if (callable == null) {
            try {
                // default handling: use no-arg constructor
                return param.newInstance();
            } catch (InstantiationException | IllegalAccessException ex) {
                throw new IllegalStateException(ex);
            }
        } else {
            try {
                return callable.call();
            } catch (Exception ex) {
                throw new IllegalStateException(ex);
            }
        }
    }
});

Parent root = loader.load();

これは複雑に見えるかもしれませんが、fxmlが必要とするコントローラークラスを決定できる場合は便利です。

FXMLによるインスタンスの作成

次のクラスを使用して、クラスのインスタンスを作成する方法を示します。

JavaFX 8

Person(@NamedArg("name") String name)アノテーションは、 @NamedArgアノテーションが使用できないため削除する@NamedArgがあります。

package fxml.sample;

import javafx.beans.NamedArg;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Person {

    public static final Person JOHN = new Person("John");

    public Person() {
        System.out.println("Person()");
    }
    
    public Person(@NamedArg("name") String name) {
        System.out.println("Person(String)");
        this.name.set(name);
    }
    
    public Person(Person person) {
        System.out.println("Person(Person)");
        this.name.set(person.getName());
    }

    private final StringProperty name = new SimpleStringProperty();

    public final String getName() {
        System.out.println("getter");
        return this.name.get();
    }

    public final void setName(String value) {
        System.out.println("setter");
        this.name.set(value);
    }

    public final StringProperty nameProperty() {
        System.out.println("property getter");
        return this.name;
    }
    
    public static Person valueOf(String value) {
        System.out.println("valueOf");
        return new Person(value);
    }
    
    public static Person createPerson() {
        System.out.println("createPerson");
        return new Person();
    }
    
}

fxmlをロードする前に、 Personクラスがすでに初期化されているものとします。

輸入に関する注意

次のfxmlの例では、importsセクションは除外されます。しかし、fxmlは

<?xml version="1.0" encoding="UTF-8"?>

fxmlファイルで使用されるすべてのクラスをインポートするimportsセクションが続きます。これらのインポートは、非静的インポートに似ていますが、処理指示として追加されます。 java.langパッケージのクラスもインポートする必要がありjava.lang

この場合、次のインポートを追加する必要があります。

<?import java.lang.*?>
<?import fxml.sample.Person?>

JavaFX 8

@NamedArg注釈付きコンストラクタ

すべてのパラメータを用いて注釈されているコンストラクタがある場合@NamedArgとの全ての値@NamedArg注釈はFXML中に存在する、コンストラクタは、これらのパラメータと一緒に使用されるであろう。

<Person name="John"/>
<Person xmlns:fx="http://javafx.com/fxml">
    <name>
        <String fx:value="John"/>
    </name>
</Person>

両方がロードされた場合、次のコンソール出力が得られます。

Person(String)

argsコンストラクタなし

適切な@NamedArg注釈付きコンストラクタがない場合、パラメータを取らないコンストラクタが使用されます。

@NamedArgアノテーションをコンストラクタから削除し、読み込みを試みます。

<Person name="John"/>

これは、パラメータなしでコンストラクタを使用します。

出力:

Person()
setter

fx:value属性

fx:value属性を使用して、その値をstatic valueOfメソッドに渡すことができますfx:valueこのメソッドは、 Stringパラメータを使用し、使用するインスタンスを返します。

<Person xmlns:fx="http://javafx.com/fxml" fx:value="John"/>

出力:

valueOf
Person(String)

fx:factory

fx:factory属性を使用すると、パラメータを取らない任意のstaticメソッドを使用してオブジェクトを作成できます。

<Person xmlns:fx="http://javafx.com/fxml" fx:factory="createPerson">
    <name>
        <String fx:value="John"/>
    </name>
</Person>

出力:

createPerson
Person()
setter

<fx:copy>

fx:copyコンストラクタを呼び出すことができます。別のfx:id指定タグのsource属性は、そのオブジェクトをパラメータとして持つコピーコンストラクタを呼び出します。

例:

<ArrayList xmlns:fx="http://javafx.com/fxml">
    <Person fx:id="p1" fx:constant="JOHN"/>
    <fx:copy source="p1"/>
</ArrayList>

出力

Person(Person)
getter

fx:constant

fx:constantstatic finalフィールドから値を得ることを可能にします。

<Person xmlns:fx="http://javafx.com/fxml" fx:constant="JOHN"/>

クラスを初期化するときに作成されたJOHNを参照するだけなので、出力は生成されません。

プロパティの設定

fxmlのオブジェクトにデータを追加する方法はいくつかあります。

<property>タグ

プロパティの名前を持つタグは、インスタンスの作成に使用される要素の子として追加できます。このタグの子は、セッターを使用してプロパティに割り当てられるか、プロパティの内容に追加されます(読み取り専用のリスト/マップのプロパティ)。

デフォルトプロパティ

クラスに@DefaultProperty注釈を付けることができます。この場合、要素は、プロパティの名前を持つ要素を使用せずに、子要素として直接追加できます。

property="value"属性

属性名として属性名を使用し、属性値として値を使用してプロパティを割り当てることができます。これは、タグの子として次の要素を追加するのと同じ効果があります。

<property>
    <String fx:value="value" />
</property>

静的セッター

プロパティはstaticセッターを使用しstatic設定することもできます。これらはsetPropertyという名前のstaticメソッドで、要素を第1のパラメータとして、値を第2のパラメータとして設定します。これらのメソッドはどのクラスでも使用でき、通常のプロパティ名の代わりにContainingClass.property使用して使用できます。

注:現在、値の型がStringない限り、対応する静的ゲッターメソッド(つまり、静的メソッド( getPropertyという静的メソッドを静的セッターと同じクラスのパラメーターとして要素を取得する静的メソッド)を使用する必要があります。

型強制

次のメカニズムは、例えばセッターメソッドのパラメーター型に合うように、割り当て中に正しいクラスのオブジェクトを取得するために使用されます。

クラスが代入可能な場合は、値そのものが使用されます。

それ以外の場合、値は次のように変換されます。

ターゲットタイプ使用される値(ソース値s
Booleanboolean Boolean.valueOf(s)
charCharacter s.toString.charAt(0)
その他のプリミティブ型またはラッパー型ターゲット型の適切なメソッドvalueOf(s.toString()) Number s場合は、ラッパー型のvalueOf(s.toString())
BigInteger BigInteger.valueOf(s.longValue())であるsNumbernew BigInteger(s.toString())それ以外の場合は
BigDecimal BigDecimal.valueOf(s.doubleValue())であるsNumbernew BigDecimal(s.toString())それ以外の場合は
Double.valueOf(s.toString())の場合s.toString()含まれてい.Long.valueOf(s.toString())それ以外の場合
Class クラスを初期化せずに現在のスレッドのコンテキストClassLoaderを使用して呼び出されたClass.forName(s.toString())
列挙型 valueOfメソッドの結果は、 sがそれぞれ小文字で始まるStringであれば、大文字の前に挿入された_区切られたすべての大文字のStringに追加変換されます。
その他返される値static valueOfタイプのマッチングパラメータ有したtargetTypeの方法において、 sまたはそのタイプのスーパークラスを

注:この動作は十分に文書化されておらず、変更される可能性があります。

public enum Location {
    WASHINGTON_DC,
    LONDON;
}
package fxml.sample;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.beans.DefaultProperty;

@DefaultProperty("items")
public class Sample {
    
    private Location loaction;

    public Location getLoaction() {
        return loaction;
    }

    public void setLoaction(Location loaction) {
        this.loaction = loaction;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }
    
    int number;

    private final List<Object> items = new ArrayList<>();

    public List<Object> getItems() {
        return items;
    }
    
    private final Map<String, Object> map = new HashMap<>();

    public Map<String, Object> getMap() {
        return map;
    }
    
    private BigInteger serialNumber;

    public BigInteger getSerialNumber() {
        return serialNumber;
    }

    public void setSerialNumber(BigInteger serialNumber) {
        this.serialNumber = serialNumber;
    }

    @Override
    public String toString() {
        return "Sample{" + "loaction=" + loaction + ", number=" + number + ", items=" + items + ", map=" + map + ", serialNumber=" + serialNumber + '}';
    }
    
}
package fxml.sample;

public class Container {

    public static int getNumber(Sample sample) {
        return sample.number;
    }

    public static void setNumber(Sample sample, int number) {
        sample.number = number;
    }

    private final String value;

    private Container(String value) {
        this.value = value;
    }

    public static Container valueOf(String s) {
        return new Container(s);
    }

    @Override
    public String toString() {
        return "42" + value;
    }

}

以下のfxmlファイルを読み込んだ結果をfxmlすると、

Sample{loaction=WASHINGTON_DC, number=5, items=[42a, 42b, 42c, 42d, 42e, 42f], map={answer=42, g=9.81, hello=42A, sample=Sample{loaction=null, number=33, items=[], map={}, serialNumber=null}}, serialNumber=4299}
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import fxml.sample.*?>

<Sample xmlns:fx="http://javafx.com/fxml/1" Container.number="5" loaction="washingtonDc">
    
    <!-- set serialNumber property (type coercion) -->
    <serialNumber>
        <Container fx:value="99"/>
    </serialNumber>
    
    <!-- Add elements to default property-->
    <Container fx:value="a"/>
    <Container fx:value="b"/>
    <Container fx:value="c"/>
    <Container fx:value="d"/>
    <Container fx:value="e"/>
    <Container fx:value="f"/>
    
    <!-- fill readonly map property -->
    <map g="9.81">
        <hello>
            <Container fx:value="A"/>
        </hello>
        <answer>
            <Container fx:value=""/>
        </answer>
        <sample>
            <Sample>
                <!-- static setter-->
                <Container.number>
                    <Integer fx:value="33" />
                </Container.number>
            </Sample>
        </sample>
    </map>
</Sample>


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow