javafx
FXML und Controller
Suche…
Syntax
- xmlns: fx = " http://javafx.com/fxml " // Namespace-Deklaration
Beispiel FXML
Ein einfaches FXML-Dokument, in dem ein AnchorPane
mit einer Schaltfläche und einem Beschriftungsknoten beschrieben wird:
<?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>
Diese FXML-Beispieldatei ist einer Controller-Klasse zugeordnet. Die Zuordnung zwischen FXML und Controller-Klasse erfolgt in diesem Fall durch Angabe des Klassennamens als Wert des Attributs fx:controller
im fx:controller="com.example.FXMLDocumentController"
der FXML: fx:controller="com.example.FXMLDocumentController"
. Die Controller-Klasse ermöglicht die Ausführung von Java-Code als Reaktion auf Benutzeraktionen für die in der FXML-Datei definierten Benutzeroberflächenelemente:
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
}
}
Ein FXMLLoader
kann zum Laden der FXML-Datei verwendet werden:
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();
}
}
Die load
führt mehrere Aktionen aus, und es ist nützlich, die Reihenfolge zu verstehen, in der sie stattfinden. In diesem einfachen Beispiel:
Der
FXMLLoader
liest und analysiert die FXML-Datei. Es erstellt Objekte, die den in der Datei definierten Elementen entsprechen, und notiert die für sie definiertenfx:id
Attribute.Da das
FXMLLoader
der FXML-Datei einfx:controller
Attribut definiert hat, erstellt derFXMLLoader
eine neue Instanz der von ihm angegebenen Klasse. Standardmäßig geschieht dies durch Aufrufen des Konstruktors ohne Argumente für die angegebene Klasse.Alle Elemente mit
fx:id
Attributen, die über Felder im Controller mit übereinstimmenden Feldnamen verfügen und die entwederpublic
(nicht empfohlen) oder mit@FXML
(empfohlen) gekennzeichnet sind, werden in die entsprechenden Felder "@FXML
". In diesem Beispiel gibt es also in der FXML-Datei einLabel
mitfx:id="label"
und einem Feld im Controller, das als definiert ist@FXML private Label label ;
Das
label
Feld wird mit der vomFXMLLoader
erstelltenLabel
InstanzFXMLLoader
.Event-Handler werden mit beliebigen Elementen in der FXML-Datei registriert, wobei die Eigenschaften
onXXX="#..."
definiert sind. Diese Ereignishandler rufen die angegebene Methode in der Controller-Klasse auf. In diesem Beispiel hat derButton
onAction="#handleButtonAction"
und der Controller definiert eine Methode@FXML private void handleButtonAction(ActionEvent event) { ... }
Wenn eine Aktion auf der Schaltfläche ausgelöst wird (z. B. wenn der Benutzer sie drückt), wird diese Methode aufgerufen. Die Methode muss einen
void
Rückgabetyp haben und kann entweder einen Parameter definieren, der dem Ereignistyp entspricht (in diesem BeispielActionEvent
), oder er kann keine Parameter definieren.Wenn die Controller-Klasse eine
initialize
definiert, wird diese Methode schließlich aufgerufen. Beachten Sie, dass dies geschieht, nachdem die@FXML
Felder@FXML
wurden. Sie können also mit dieser Methode sicher auf sie@FXML
und werden mit den Instanzen initialisiert, die den Elementen in der FXML-Datei entsprechen. Die Methodeinitialize()
kann entweder keine Parameter oder eineURL
und einResourceBundle
. Im letzteren Fall werden diese Parameter mit derURL
FXMLLoader
die den Speicherort der FXML-Datei darstellt, und einem beliebigenResourceBundle
, das imFXMLLoader
überloader.setResources(...)
. Beide könnennull
wenn sie nicht festgelegt wurden.
Verschachtelte Controller
Es ist nicht erforderlich, die gesamte Benutzeroberfläche in einer einzigen FXML mit einem einzigen Controller zu erstellen.
Mit dem <fx:include>
-Tag kann eine fxml-Datei in eine andere eingefügt werden. Der Controller der mitgelieferten fxml kann wie jedes andere Objekt, das vom FXMLLoader
erstellt wurde, in den Controller der enthaltenen Datei FXMLLoader
.
Dies geschieht durch Hinzufügen des Attributs fx:id
zum Element <fx:include>
. Auf diese Weise wird der Controller der mitgelieferten fxml in das Feld mit dem Namen <fx:id value>Controller
eingefügt.
Beispiele:
fx: ID-Wert | Feldname für die Injektion |
---|---|
foo | fooController |
antwort42 | answer42Controller |
xYz | xYzController |
Beispiel fxmls
Zähler
Dies ist ein fxml ein enthält StackPane
mit einem Text
- Knoten. Der Controller für diese fxml-Datei ermöglicht das Abrufen des aktuellen Zählerwerts sowie das Inkrementieren des Zählers:
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;
}
}
Einschließlich 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
Der Controller der mitgelieferten fxml wird in diesen Controller injiziert. Hier wird der Handler für das onAction
Ereignis für den Button
verwendet, um den Zähler zu 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();
}
}
Die fxmls können wie folgt geladen werden, vorausgesetzt, der Code wird von einer Klasse in demselben Paket wie outer.fxml
:
Parent parent = FXMLLoader.load(getClass().getResource("outer.fxml"));
Blöcke definieren und
Manchmal muss ein Element außerhalb der üblichen Objektstruktur in der fxml erstellt werden.
Hier kommen Define Blocks ins Spiel:
Inhalte in einem <fx:define>
-Element werden nicht zu dem Objekt hinzugefügt, das für das übergeordnete Element erstellt wurde.
Jedes untergeordnete Element von <fx:define>
benötigt ein fx:id
Attribut.
Auf diese Weise erstellte Objekte können später mit dem Element <fx:reference>
oder mit der Ausdrucksbindung <fx:reference>
.
Das Element <fx:reference>
kann verwendet werden, um auf ein beliebiges Element mit einem fx:id
Attribut zu verweisen, das vor dem <fx:reference>
-Element behandelt wird, indem derselbe Wert verwendet wird wie das fx:id
Attribut des referenzierten Elements in source
- Attribut des <fx:reference>
Element.
<?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>
Daten an FXML übergeben - Zugriff auf vorhandene Controller
Problem: Einige Daten müssen an eine Szene übergeben werden, die aus einem Fxml geladen wurde.
Lösung
Geben Sie einen Controller mit dem Attribut fx:controller
und FXMLLoader
die während des Ladevorgangs erstellte Controller-Instanz aus der zum Laden des fxml verwendeten FXMLLoader
Instanz ab.
Fügen Sie Methoden hinzu, um die Daten an die Controller-Instanz zu übergeben, und behandeln Sie die Daten in diesen Methoden.
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>
Regler
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);
}
}
Code, der zum Laden der fxml verwendet wird
String data = "Hello World!";
FXMLLoader loader = new FXMLLoader(getClass().getResource("test.fxml"));
Parent root = loader.load();
TestController controller = loader.<TestController>getController();
controller.setData(data);
Daten an FXML übergeben - Angabe der Controller-Instanz
Problem: Einige Daten müssen an eine Szene übergeben werden, die aus einem Fxml geladen wurde.
Lösung
FXMLLoader
Sie den Controller mit der FXMLLoader
Instanz ein, die später zum Laden der fxml verwendet wird.
Stellen Sie sicher, dass der Controller die relevanten Daten enthält, bevor Sie die fxml laden.
Hinweis: In diesem Fall darf die fxml-Datei nicht das Attribut fx:controller
enthalten.
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>
Regler
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);
}
}
Code, der zum Laden der fxml verwendet wird
String data = "Hello World!";
FXMLLoader loader = new FXMLLoader(getClass().getResource("test.fxml"));
TestController controller = new TestController(data);
loader.setController(controller);
Parent root = loader.load();
Übergabe von Parametern an FXML - mithilfe einer ControllerFactory
Problem: Einige Daten müssen an eine Szene übergeben werden, die aus einem Fxml geladen wurde.
Lösung
Geben Sie eine Controller-Factory an, die für die Erstellung der Controller verantwortlich ist. Übergeben Sie die Daten an die von der Fabrik erstellte Controller-Instanz.
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>
Regler
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);
}
}
Code, der zum Laden der fxml verwendet wird
String data = "Hallo Welt!";
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();
Dies mag komplex erscheinen, aber es kann nützlich sein, wenn die fxml entscheiden kann, welche Controller-Klasse sie benötigt.
Instanzerstellung in FXML
Die folgende Klasse zeigt, wie Instanzen von Klassen erstellt werden können:
Die Annotation in Person(@NamedArg("name") String name)
muss entfernt werden, da die Annotation @NamedArg
nicht verfügbar ist.
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();
}
}
Angenommen, die Person
Klasse wurde vor dem Laden der fxml bereits initialisiert.
Ein Hinweis zu den Einfuhren
Im folgenden fxml-Beispiel wird der Importabschnitt ausgelassen. Die fxml sollte jedoch mit beginnen
<?xml version="1.0" encoding="UTF-8"?>
gefolgt von einem Importabschnitt, in dem alle in der fxml-Datei verwendeten Klassen importiert werden. Diese Importe ähneln nicht-statischen Importen, werden jedoch als Verarbeitungsanweisungen hinzugefügt. Sogar Klassen aus dem java.lang
Paket müssen importiert werden.
In diesem Fall sollten folgende Importe hinzugefügt werden:
<?import java.lang.*?>
<?import fxml.sample.Person?>
@NamedArg
Konstruktor mit Anmerkungen
Wenn es einen Konstruktor gibt, bei dem jeder Parameter mit @NamedArg
und alle Werte der @NamedArg
Annotationen in der fxml vorhanden sind, wird der Konstruktor mit diesen Parametern verwendet.
<Person name="John"/>
<Person xmlns:fx="http://javafx.com/fxml">
<name>
<String fx:value="John"/>
</name>
</Person>
Wenn beide geladen sind, führt dies zu folgender Konsolenausgabe:
Person(String)
Kein Argumentkonstruktor
Wenn kein geeigneter mit @NamedArg
versehener @NamedArg
Konstruktor verfügbar ist, wird der Konstruktor verwendet, der keine Parameter verwendet.
Entfernen Sie die Annotation @NamedArg
aus dem Konstruktor und versuchen Sie, zu laden.
<Person name="John"/>
Dadurch wird der Konstruktor ohne Parameter verwendet.
Ausgabe:
Person()
setter
fx:value
Wertattribut
Das Attribut fx:value
kann verwendet werden, um seinen Wert an eine static
valueOf
Methode zu übergeben, die einen String
Parameter verwendet und die zu verwendende Instanz valueOf
.
Beispiel
<Person xmlns:fx="http://javafx.com/fxml" fx:value="John"/>
Ausgabe:
valueOf
Person(String)
fx:factory
Das Attribut fx:factory
ermöglicht die Erstellung von Objekten mit beliebigen static
Methoden, die keine Parameter verwenden.
Beispiel
<Person xmlns:fx="http://javafx.com/fxml" fx:factory="createPerson">
<name>
<String fx:value="John"/>
</name>
</Person>
Ausgabe:
createPerson
Person()
setter
<fx:copy>
Mit fx:copy
ein Kopierkonstruktor aufgerufen werden. Die Angabe der fx:id
eines anderen der source
- Attribut des Tags wird die Copykonstruktor mit diesem Objekt als Parameter aufrufen.
Beispiel:
<ArrayList xmlns:fx="http://javafx.com/fxml">
<Person fx:id="p1" fx:constant="JOHN"/>
<fx:copy source="p1"/>
</ArrayList>
Ausgabe
Person(Person)
getter
fx:constant
fx:constant
ermöglicht das Abrufen eines Wertes aus einem static final
Endfeld.
Beispiel
<Person xmlns:fx="http://javafx.com/fxml" fx:constant="JOHN"/>
erzeugt keine Ausgabe, da diese nur auf JOHN
verweist, das beim Initialisieren der Klasse erstellt wurde.
Eigenschaften festlegen
Es gibt mehrere Möglichkeiten, einem Objekt in fxml Daten hinzuzufügen:
<property>
-Tag
Ein Tag mit dem Namen einer Eigenschaft kann als untergeordnetes Element eines Elements hinzugefügt werden, das zum Erstellen einer Instanz verwendet wird. Das untergeordnete Element dieses Tags wird der Eigenschaft mit dem Setter zugewiesen oder dem Inhalt der Eigenschaft hinzugefügt (readonly list / map properties).
Standardeigenschaft
Eine Klasse kann mit der Annotation @DefaultProperty
kommentiert werden. In diesem Fall können Elemente direkt als untergeordnetes Element hinzugefügt werden, ohne dass ein Element mit dem Namen der Eigenschaft verwendet wird.
property="value"
-Attribut
Eigenschaften können mit dem Eigenschaftsnamen als Attributnamen und dem Wert als Attributwert zugewiesen werden. Dies hat den gleichen Effekt wie das Hinzufügen des folgenden Elements als untergeordnetes Element des Tags:
<property>
<String fx:value="value" />
</property>
statische Setzer
Eigenschaften können auch mit static
Setzern eingestellt werden. Dies sind static
Methoden mit dem Namen setProperty
, bei denen das Element als erster Parameter und der Wert als zweiter Parameter festgelegt wird. Diese Methoden können in jeder Klasse verwendet werden und können mit ContainingClass.property
anstelle des üblichen Eigenschaftennamens verwendet werden.
Anmerkung: Derzeit scheint es notwendig zu sein, eine entsprechende statische Getter-Methode zu haben (dh eine statische Methode mit dem Namen getProperty
die das Element als Parameter in derselben Klasse wie der statische Setzer verwendet), damit dies funktioniert, sofern der getProperty
String
.
Typ Zwang
Der folgende Mechanismus wird verwendet, um ein Objekt der richtigen Klasse während Zuweisungen abzurufen, z. B. um den Parametertyp einer Setter-Methode anzupassen.
Wenn die Klassen zuweisbar sind, wird der Wert selbst verwendet.
Andernfalls wird der Wert wie folgt konvertiert
Zieltyp | verwendeter Wert (Quellwert s ) |
---|---|
Boolean , boolean | Boolean.valueOf(s) |
char , Character | s.toString.charAt(0) |
anderer primitiver Typ oder Wrapper-Typ | geeignete Methode für den valueOf(s.toString()) , falls s eine Number , valueOf(s.toString()) für den Wrapper-Typ |
BigInteger | BigInteger.valueOf(s.longValue()) ist s ist eine Number , ansonsten new BigInteger(s.toString()) |
BigDecimal | BigDecimal.valueOf(s.doubleValue()) ist s eine Number , ansonsten new BigDecimal(s.toString()) |
Nummer | Double.valueOf(s.toString()) wenn s.toString() enthält . , Long.valueOf(s.toString()) ansonsten |
Class | Class.forName(s.toString()) mit dem Kontext ClassLoader des aktuellen Threads aufgerufen, ohne die Klasse zu initialisieren |
enum | Das Ergebnis der valueOf Methode umgewandelt zusätzlich zu einem Großbuchstaben String getrennt durch _ vor jeder Großbuchstabe eingefügt, wenn s a String , der mit einem Kleinbuchstaben beginnt , |
andere | Der von einer static valueOf Methode im targetType zurückgegebene Wert, dessen Parameter mit dem Typ s oder einer Superklasse dieses Typs übereinstimmt |
Hinweis: Dieses Verhalten ist nicht gut dokumentiert und kann Änderungen unterliegen.
Beispiel
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;
}
}
Das Ergebnis des Ladens der unten angegebenen fxml
Datei wird 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>