Введение в FXML
Содержание
Оригинал: https://openjfx.io/javadoc/11/javafx.fxml/javafx/fxml/doc-files/introduction_to_fxml.html
Краткий обзор
FXML-это скриптовый язык разметки на основе XML для построения графических объектов Java. Он обеспечивает удобную альтернативу построению таких объектов в процедурном коде и идеально подходит для определения пользовательского интерфейса приложения JavaFX, поскольку иерархическая структура XML-документа тесно связана со структурой графа сцены JavaFX.
Этот документ знакомит с языком разметки FXML и объясняет, как его можно использовать для упрощения разработки приложений JavaFX.
Элементы
В FXML XML-элемент представляет собой один из следующих вариантов:
- Экземпляр класса
- Свойство экземпляра класса
- Свойство "static"
- Блок "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. Свойства также могут быть заданы с помощью вложенных элементов свойств. Элементы свойств более подробно рассматриваются далее в этом разделе. Атрибуты свойств обсуждаются в следующем разделе.
Классы, которые не соответствуют соглашениям о компонентах, также могут быть созданы в FXML с использованием объекта, называемого «builder» (построитель). Подробнее о построителях рассказывается чуть позже.
Карты
Внутри загрузчик FXML использует экземпляр com.sun.javafx.fxml.BeanAdapter для обертывания экземпляра объекта и вызова его методов установки. Этот (в настоящее время) private класс реализует интерфейс java.util.Map и позволяет вызывающему абоненту получать и устанавливать значения свойств Bean в виде пар ключ/значение.
<HashMap foo="123" bar="456"/>
fx:value
<String fx:value="Hello, World!"/> <Double fx:value="1.0"/> <Boolean fx:value="false"/>
Пользовательские классы, определяющие статический метод valueOf(String), также могут быть построены таким образом.
fx:factory
<FXCollections fx:factory="observableArrayList"> <String fx:value="A"/> <String fx:value="B"/> <String fx:value="C"/> </FXCollections>
Построители.
Поддержка Builder в FXML обеспечивается двумя интерфейсами. Интерфейс 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"/>
Обратите внимание, что в отличие от типов соглашения о компонентах (JavaBean), которые создаются при обработке начального тега элемента, объекты, созданные построителем, не создаются до тех пор, пока не будет достигнут закрывающий тег элемента. Это связано с тем, что все необходимые аргументы могут быть недоступны, пока элемент не будет полностью обработан. Например, объект Color в предыдущем примере можно также записать как:
<Color> <red>1.0</red> <green>0.0</green> <blue>0.0</blue> </Color>
Экземпляр Color не может быть полностью построен, пока не будут известны все три компонента цвета.
При обработке разметки для объекта, который будет построен конструктором, экземпляры Builder обрабатываются как объекты значений - если Builder реализует интерфейс Map, метод put() используется для установки значений атрибутов построителя. В противном случае построитель оборачивается в BeanAdapter, и предполагается, что его свойства предоставляются через стандартные установщики Bean.
<fx:include>
Тег
<fx:include source="filename"/>
Например, учитывая следующую разметку:
<?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"/>
итоговый граф сцены будет содержать VBox в качестве корневого объекта с одной кнопкой в качестве дочернего узла.
Обратите внимание на использование префикса пространства имен «fx». Это зарезервированный префикс, который определяет ряд элементов и атрибутов, которые используются для внутренней обработки исходного файла FXML. Обычно он объявляется в корневом элементе документа FXML. Другие функции, предоставляемые пространством имен «fx», описаны в следующих разделах.
<fx:include> также поддерживает атрибуты для указания имени пакета ресурсов, который должен использоваться для локализации включенного содержимого, а также набор символов, используемый для кодирования исходного файла. Разрешение ресурсов обсуждается в следующем разделе.
<fx:include source="filename" resources="resource_file" charset="utf-8"/>
<fx:constant>
<Button> <minHeight><Double fx:constant="NEGATIVE_INFINITY"/></minHeight> </Button>
<fx:reference>
Например, следующая разметка назначает ранее определенный экземпляр изображения с именем "myImage" свойству "image" элемента управления ImageView:
<ImageView> <image> <fx:reference source="myImage"/> </image> </ImageView>
Обратите внимание, что, поскольку также можно разыменовать переменную с помощью оператора разрешения переменной атрибута (обсуждаемого далее в разделе Атрибуты), fx:reference обычно используется только тогда, когда ссылочное значение должно быть указано как элемент, например при добавлении ссылки в коллекцию:
<ArrayList> <fx:reference source="element1"/> <fx:reference source="element2"/> <fx:reference source="element3"/> </ArrayList>
В большинстве других случаев использование атрибута проще и лаконичнее.
<fx:copy>
На данный момент ни один класс платформы JavaFX не предоставляет такого конструктора копирования, поэтому этот элемент предоставляется в первую очередь для использования разработчиками приложений. Это может измениться в будущем выпуске.
<fx:root>
Элементы - свойства.
Элементы, имена тегов которых начинаются со строчной буквы, представляют свойства объекта. Элемент свойства может представлять одно из следующего:
- Свойство - установщик
- Свойство - список только для чтения
- Свойство - карта только для чтения
Свойство - установщик
Например, следующий FXML создает экземпляр класса Label и устанавливает значение свойства 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 использует метод coerce() класса BeanAdapter для выполнения любых необходимых преобразований типов. Этот метод способен выполнять базовые преобразования примитивных типов, такие как String в boolean или int в double, а также преобразовывать String в Class или String в Enum. Дополнительные преобразования могут быть реализованы путем определения статического метода valueOf() для целевого типа.
Свойств - список (только для чтения).
Например, свойство "children" javafx.scene.Group является свойством списка только для чтения, представляющим дочерние узлы группы:
<?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().
Свойство - карта (только для чтения).
Свойство "properties" javafx.scene.Node - это пример свойства карты только для чтения. Следующая разметка устанавливает свойства "foo" и "bar" экземпляра метки в "123" и "456" соответственно:
<?import javafx.scene.control.*?> <Button> <properties foo="123" bar="456"/> </Button>
Свойства по умолчанию
Например, начиная с javafx.scene.layout.Pane (суперкласс javafx.scene.layout.VBox) определяет свойство по умолчанию "children", элемент <children> не требуется; загрузчик автоматически добавит подэлементы VBox в коллекцию "children" контейнера:
<?import javafx.scene.*?> <?import javafx.scene.shape.*?> <VBox xmlns:fx="http://javafx.com/fxml"> <Button text="Click Me!"/> ... </VBox>
Обратите внимание, что свойства по умолчанию не ограничиваются коллекциями. Если свойство элемента по умолчанию ссылается на скалярное значение, то любой подэлемент этого элемента будет установлен в качестве значения свойства.
Например, начиная с javafx.scene.control.ScrollPane определяет свойство по умолчанию "content", панель прокрутки, содержащая текстовую область, поскольку ее содержимое может быть указано следующим образом:
<ScrollPane> <TextArea text="Once upon a time..."/> </ScrollPane>
Использование свойств по умолчанию может значительно снизить многословность разметки FXML.
Статические свойства.
Статические свойства имеют префикс с именем класса, который их определяет. Например, следующий FXML вызывает статический метод set для свойств 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, определяют аналогичные свойства.
Как и в случае со свойствами экземпляра, статические элементы свойств обычно используются, когда значение свойства не может быть эффективно представлено значением атрибута. В противном случае атрибуты статических свойств (обсуждаемые в следующем разделе), как правило, дают более сжатую и читаемую разметку.
Блоки define.
Например, при работе с переключателями обычно определяется группа переключателей ToggleGroup, которая будет управлять состоянием выбора кнопок. Эта группа не является частью самого графа сцены, поэтому ее не следует добавлять к родительским кнопкам. Блок define можно использовать для создания группы кнопок без вмешательства в общую структуру документа:
<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>
Элементам в блоках define обычно присваивается идентификатор id, который позже может быть использован для ссылки на значение элемента. Идентификаторы более подробно рассматриваются в последующих разделах.
Атрибуты.
Атрибут в FXML может представить одно из следующего:
- Свойство экземпляра класса
- Статическое свойство "static"
- Обработчик событий
Каждый из них более подробно обсуждается в следующих разделах.
Свойства экземпляра.
<?import javafx.scene.control.*?> <Button text="Click Me!"/>
<Rectangle fx:id="rectangle" x="10" y="10" width="320" height="240" fill="#ff0000"/>
В отличие от элементов свойства, которые применяются, поскольку они обрабатываются, не применяются атрибуты свойства, пока закрывающий тэг их соответствующего элемента не достигается. Это делается прежде всего, чтобы облегчить случай, где значение атрибута зависит от некоторой информации, которая не будет доступна, пока контент элемента не был полностью обработан (например, выбранные индексируют управления TabPane, которое не может быть установлено, пока все вкладки не были добавлены).
Другое основное отличие между атрибутами свойства и элементами свойства в FXML - то, что атрибуты поддерживают много "операторов разрешения", которые расширяют их функциональность. Следующие операторы поддерживаются и обсуждаются более подробно ниже:
- Разрешение расположения
- Разрешение ресурса
- Разрешение переменной
Разрешение расположения.
Например, следующая разметка создает ImageView и заполняет его данными изображения из файла my_image.png, который, как предполагается, находится по пути относительно текущего файла FXML:
<ImageView> <image> <Image url="@my_image.png"/> </image> </ImageView>
Поскольку Image является неизменяемым объектом, для его построения требуется строитель. В качестве альтернативы, если Image должен был определить метод factory valueOf(URL), представление изображения могло бы быть заполнено следующим образом:
<ImageView image="@my_image.png"/>
Значение атрибута "image" будет преобразовано в URL-адрес загрузчиком FXML, а затем приведено к изображению с помощью метода valueOf().
Обратите внимание, что значения пробелов в 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!".
Разрешение переменной.
<fx:define> <ToggleGroup fx:id="myToggleGroup"/> </fx:define> ... <RadioButton text="A" toggleGroup="$myToggleGroup"/> <RadioButton text="B" toggleGroup="$myToggleGroup"/> <RadioButton text="C" toggleGroup="$myToggleGroup"/>
Escape-последовательности
<Label text="\$10.00"/>
Привязка выражения.
Переменные атрибутов, как показано выше, разрешаются один раз во время загрузки. Более поздние обновления значения переменных не отражаются автоматически ни в каких свойствах, которым было присвоено значение. Во многих случаях этого достаточно; однако часто бывает удобно "привязать" значение свойства к переменной или выражению, чтобы изменения переменной автоматически распространялись на целевое свойство. Для этого можно использовать привязки выражений.
<TextField fx:id="textField"/> <Label text="${textField.text}"/>
По мере ввода текста пользователем текстовое содержимое метки будет автоматически обновляться.
Также поддерживаются более сложные выражения. Ниже приведен список поддерживаемых констант и операторов:
Константа / Оператор | Описание |
---|---|
"string" 'string' |
Строковая константа |
true false |
Булева константа |
null | Константа, представляющая нулевое значение |
50.0 3e5 42 |
Числовая константа |
- (unary operator) |
Унарный оператор минус, применяемый к числу |
! (unary operator) |
Унарное отрицание булева |
+ - * / % |
Числовые двоичные операторы |
&& || | Логические бинарные операции |
> >= < <= == != |
Бинарные операторы сравнения. Оба аргумента должны быть Сопоставимы по типу |
Статические Свойства.
<GridPane> <children> <Label text="My Label" GridPane.rowIndex="0" GridPane.columnIndex="0"/> </children> </TabPane>
Обработчики событий.
Атрибуты обработчика событий являются удобным средством привязки поведения к элементам документа. Любой класс, определяющий метод setOnEvent (), может быть назначен обработчиком событий в разметке.
FXML поддерживает три типа атрибутов обработчика событий: обработчики событий сценария, обработчики событий метода контроллера и выражения. Каждый из них обсуждается ниже.
Обработчики событий скриптов.
<?language javascript?> ... <VBox> <children> <Button text="Click Me!" onAction="java.lang.System.out.println('You clicked me!');"/> </children> </VBox>
Обработчики событий Метода контроллера.
Обработчик событий метода контроллера - это метод, определенный в документе "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!"); } }
функция 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 EventHandler<ActionEvent> onActionHandler = new EventHandler<>() { ... } ... }
Обратите внимание, что другие типы выражений, такие как выражения привязки, в этом контексте не поддерживаются.
Специальные обработчики для коллекций и свойств.
Коллекции и свойства объектов нельзя прослушивать с помощью методов setOnEvent(). По этой причине необходимо использовать специальные методы обработки. ObservableList, ObservableMap или ObservableSet используют специальный атрибут onChange, который указывает на метод обработчика с ListChangeListner.Change, MapChangeListener.Change или SetChangeListener.Change параметр соответственно.
<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"/>
Обратите внимание, что коллекции и свойства в настоящее время не поддерживают обработчики сценариев.
Сценарии.
Например, следующая разметка определяет функцию handleButtonAction(), которая вызывается обработчиком действия, прикрепленным к элементу Button:
<?language javascript?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <VBox xmlns:fx="http://javafx.com/fxml"> <fx:script> importClass(java.lang.System); function handleButtonAction(event) { 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"/> <children> <Button text="Click Me!" onAction="handleButtonAction(event);"/> </children> </VBox>
example.js
importClass(java.lang.System); function handleButtonAction(event) { System.out.println('You clicked me!'); }
Часто предпочтительнее отделять код от разметки таким образом, поскольку многие текстовые редакторы поддерживают подсветку синтаксиса для различных языков сценариев, поддерживаемых JVM. Это также может помочь улучшить читабельность исходного кода и разметки.
Обратите внимание, что блоки сценариев не ограничиваются определением функций обработчика событий. Код скрипта выполняется по мере его обработки, поэтому его также можно использовать для динамической настройки структуры результирующего вывода. В качестве простого примера следующий FXML включает блок скрипта, который определяет переменную с именем "LabelText". Значение этой переменной используется для заполнения свойства text экземпляра Label:
<fx:script> var myText = "This is the text of my label."; </fx:script> ... <Label text="$myText"/>
Предупреждение:Начиная с JavaFX 8, функция importClass() javascript больше не поддерживается. Вы должны использовать полные имена, как в приведенном выше примере, или загрузить сценарий совместимости nashorn.
load("nashorn:mozilla_compat.js"); importClass(java.lang.System); function handleButtonAction(event) { System.out.println('You clicked me!'); }
Контроллеры.
Хотя может быть удобно писать простые обработчики событий в скриптах, встроенных или определенных во внешних файлах, часто предпочтительнее определять более сложную логику приложения на скомпилированном, строго типизированном языке, таком как Java. Как обсуждалось ранее, атрибут fx:controller позволяет вызывающему объекту связать класс "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!"); } }); } }
@FXML
Например, контроллеры из предыдущих примеров можно было бы переписать следующим образом:
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, чтобы позволить разметке, определенной в документе контроллера, вызывать его. Во втором примере поле кнопки аннотируется, чтобы загрузчик мог установить его значение. Метод initialize() также аннотируется.
Вложенные Контроллеры
<VBox fx:controller="com.foo.MainController"> <fx:include fx:id="dialog" source="dialog.fxml"/> ... </VBox>
MainController.java
public class MainController extends Controller { @FXML private Window dialog; @FXML private DialogController dialogController; ... }
при вызове метода initialize() контроллера поле dialog будет содержать корневой элемент, загруженный из вложенного "dialog.fxml", а поле dialogController будет содержать вложенный контроллер. Затем главный контроллер может вызывать методы на включенном контроллере, например, для заполнения и отображения диалогового окна. Обратите внимание, что поскольку содержимое файла, на который ссылается fx:include, в противном случае стало бы частью графа сцены, охватываемого main_window_content.fxml, необходимо обернуть fx:include с помощью fx:define, чтобы разделить графики сцен обоих окон.
FXMLLoader
Класс 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();
Пользовательские Компоненты.
Например, следующая разметка определяет структуру простого пользовательского элемента управления, содержащего TextField и экземпляр Кнопки. Корневой контейнер определяется как экземпляр 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> тег создает ссылку на ранее определенный корневой элемент. Значение этого элемента получается, вызывая getRoot () метод FXMLLoader.
В следующем примере CustomControl class расширяет 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);
FXML
<HBox> <CustomControl text="Hello World!"/> </HBox>