JavaFX: как подключить FXML к коду

JavaFX FXML — это формат XML, который позволяет создавать графические интерфейсы аналогично тому, как вы создаете веб-интерфейсы в HTML. Таким образом, FXML позволяет вам отделить код макета JavaFX от остального кода вашего приложения. Это очищает как код макета, так и остальную часть кода приложения.

FXML может использоваться как для компоновки макета всего графического интерфейса приложения, так и просто части, например макета одной части формы, вкладки, диалога и т. д.

Пример

Ниже приведен пример, который составляет простой графический интерфейс:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>

<VBox>
    <children>
        <Label text="Hello world FXML"/>
    </children>
</VBox>

В этом примере определяется VBox, содержащий одну метку в качестве дочернего элемента. Он является компонентом макета JavaFX. Метка просто показывает текст в графическом интерфейсе.

Первая строка в документе FXML — это стандартная первая строка документов XML.

Следующие две строки являются операторами импорта. В FXML вам нужно импортировать классы, которые вы хотите использовать. Классы JavaFX и основные классы Java, используемые тут, должны быть импортированы.

После операторов импорта у вас есть фактический состав GUI. Компонент VBox объявляется, а внутри его дочернего свойства объявляется один компонент Label. В результате экземпляр Label будет добавлен в свойство children экземпляра VBox.

Загрузка файла

Чтобы загрузить файл FXML и создать компоненты графического интерфейса JavaFX, которые файл объявляют, вы используете класс FXMLLoader(javafx.fxml.FXMLLoader).

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.net.URL;

public class FXMLExample extends Application{

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(new URL("file:///C:/data/hello-world.fxml"));
        VBox vbox = loader.load();

        Scene scene = new Scene(vbox);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

Чтобы этот пример работал, файл FXML должен быть расположен в C: \ data \ hello-world.fxml. Как видите, местоположение файла задается с помощью метода setLocation(). Корневой компонент GUI (объект VBox) получается с помощью метода load().

Импорт классов

Чтобы использовать класс Java в FXML, будь то компонент GUI или обычный класс, его нужно импортировать:


Этот оператор импорта FXML импортирует класс javafx.scene.layout.VBox.

Создание объектов

FXML может создавать как объект GUI, так и объекты не-JavaFX.

Создание объектов с помощью элементов FXML и конструкторов без аргументов

Самый простой способ создания объектов — это использование элемента FXML в файле. Имена элементов совпадают с именами классов Java без имен пакетов. После того, как вы импортировали класс с помощью оператора импорта, можете использовать его имя в качестве имени элемента.

В следующем примере имена элементов VBox и Label действительны, потому что эти два класса объявлены с инструкциями импорта ранее в файле:






    
        


Для создания объектов с использованием таких элементов FXML необходимо, чтобы класс созданного объекта имел конструктор без аргументов.

Создание объектов с помощью метода valueOf()

Способ создания объектов с помощью метода valueOf() заключается в вставке атрибута значения в элемент FXML. Вот пример:





Вот как должен выглядеть соответствующий MyClass для работы:

public MyClass {
    public static MyClass valueOf(String value) {
        return new MyClass(value);
    }

    private String value = null;

    public MyClass(String value) {
        this.value = value;
    }
}

Обратите внимание на статический метод valueOf(), который принимает строку Java в качестве параметра. Этот метод вызывается FXMLLoader, когда он видит элемент MyClass в файле FXML. Объект, возвращаемый методом valueOf(), — это то, что вставляется в графический интерфейс, составленный в файле. Приведенный выше FXML не содержит никаких других элементов, кроме элемента MyClass, но он может.

Имейте в виду, что любой объект, возвращаемый методом valueOf(), будет использоваться в графе объектов (составленном GUI). Если возвращаемый объект не является экземпляром класса, содержащего метод valueOf(), а является экземпляром какого-то другого класса, то этот объект все равно будет использоваться в графе объектов. Имя элемента используется только для поиска класса, содержащего метод valueOf() (когда элемент FXML содержит атрибут value).

Создание объектов с помощью factory методов

В некотором смысле метод valueOf() также является factory методом, который создает объекты на основе параметра String. Но вы также можете заставить FXMLLoader вызывать другие методы.

Для этого вам нужно вставить атрибут fx: factory. Значением атрибута fx: factory должно быть имя factory метода для вызова. Вот пример:





Класс MyClass должен выглядеть так, чтобы работал приведенный выше пример FXML:

public MyClass {
    public static MyClass instance() {
        return new MyClass();
    }
}

Обратите внимание на метод instance(). На этот метод ссылается атрибут fx: factory во фрагменте FXML выше.

Обратите внимание, что factory метод должен быть методом без аргументов, чтобы вызывать его из атрибута fx: factory.

Свойства

Некоторые объекты JavaFX имеют свойства. Вы можете установить их значения двумя способами.

  1. использовать атрибут XML для установки значения свойства;
  2. использовать вложенный элемент XML для установки значения свойства.

Чтобы понять, как лучше установить свойства в элементах, давайте рассмотрим пример:






    
               

Этот пример показывает 3 примера свойств.

  1. атрибут spacing в элементе VBox. Значение, установленное в атрибуте spacing, передается в качестве параметра методу setSpacing() объекта VBox, созданного на основе элемента VBox;
  2. дочерний элемент, вложенный в элемент VBox. Этот элемент соответствует методу getChildren() класса VBox. Элементы, вложенные в дочерний элемент, будут преобразованы в компоненты JavaFX, которые добавляются в коллекцию, полученную из метода getChildren() объекта VBox, представленного родительским элементом VBox;
  3. текстовые атрибуты двух элементов Label, вложенных в дочерние элементы. Значения текстовых атрибутов будут переданы в качестве параметров свойству setText() объектов Label, созданных элементами Label.

Соответствие имени свойства

FXML рассматривает «свойства» как переменные-члены, доступ к которым осуществляется через методы получения и установки. Например, getText() и setText().

Как видно из примера в предыдущем разделе, имена свойств классов JavaFX сопоставляются с именами атрибутов и элементов следующим образом:

  • Удалите все get / set в имени свойства.
  • Преобразуйте первый оставшийся символ имени свойства в нижний регистр.

Таким образом, метод getChildren будет сначала преобразован в Children, а затем в children. Аналогично, метод setText будет сокращен до Text, а затем до Text.

Свойства по умолчанию

Компонент JavaFX может иметь свойство по умолчанию. Это означает, что если элемент FXML содержит дочерние элементы, которые не вложены в элемент свойства, то предполагается, что дочерние элементы принадлежат свойству по умолчанию.

Давайте посмотрим на пример. Класс VBox имеет свойство children в качестве свойства по умолчанию. Это означает, что мы можем опустить элемент детей. Таким образом, этот FXML:






    
        

можно сократить до:






    

Предполагается, что два элемента Label принадлежат свойству VBox по умолчанию, которое является дочерним свойством.

Свойство по умолчанию помечается аннотацией JavaFX @DefaultProperty(value = «propertyName»), где значением является имя свойства, которое должно быть свойством по умолчанию. Например, объявление @DefaultProperty(value = «children») сделало бы свойство children свойством по умолчанию.

Пространство имен

Пространство имен вы можете установить в корневом элементе ваших файлов FXML. Оно необходимо для некоторых атрибутов FXML, таких как атрибут fx: id. Установка пространства имен:






Пространство имен FXML объявляется объявлением атрибута xmlns: fx = «https://javafx.com/fxml».

Идентификаторы элементов

Эти идентификаторы могут использоваться для ссылки на элементы FXML в других местах файла. Задание идентификатора для элемента осуществляется с помощью атрибута id из пространства имен:






    

Обратите внимание на объявление атрибута fx: id = «label1» в элементе Label. Этот атрибут объявляет идентификатор этого элемента Label. Теперь на этот конкретный элемент Label можно ссылаться через идентификатор label1 в другом месте документа. Например, этот идентификатор можно использовать для ссылки на элемент FXML из CSS.

Обработчики событий

Можно установить обработчики событий для объектов из файла FXML, который определяет объекты. Вы можете предпочесть устанавливать расширенные обработчики событий из кода Java, но для простых обработчиков событий установка их из FXML может подойти. Чтобы определить обработчик события, вам нужно использовать элемент script:







    

В этом примере показаны две интересные концепции:

  1. Добавление прослушивателя событий в компонент из FXML. Элемент Button объявляет прослушиватель событий через его атрибут onAction. Значение атрибута объявляет вызов функцииactToClick(), который определен в элементе script далее в файле FXML.
  2. Ссылка на компонент через его идентификатор из файла FXML. Внутри метода reactToClick(), объявленного в элементе script, на элемент Label ссылается его идентификатор label1, с помощью этого оператора:
label1.setText("Button clicked");

Атрибут слушателя события onAction соответствует событию onAction компонента Button. Вы также можете установить прослушиватель событий через Java-код, с помощью метода Button setOnAction(). Вы также можете установить прослушиватели для других событий в FXML, сопоставив их методы прослушивателя событий из соответствующего компонента JavaFX с атрибутом FXML, используя те же правила сопоставления имен, что и для других свойств.

CSS-стили

Можно стилизовать компоненты, объявленные в файле. Вы можете сделать это, встроив элемент стиля в элемент FXML:






    

В этом примере для свойства CSS -fx-padding установлено значение 10, а для свойства -fx-border-width — значение 3. Поскольку элемент style вложен в элемент button, эти стили CSS будут применены к этому элементу button.

Классы контроллера

Класс контроллера может связывать компоненты графического интерфейса, объявленные в файле, делая объект контроллера действующим в качестве посредника (шаблон проектирования).

Есть два способа установить контроллер для файла:

  1. указать его в файле;
  2. установить экземпляр класса контроллера для экземпляра FXMLLoader, используемого для загрузки документа FXML.

Указание класса контроллера

Класс контроллера указывается в корневом элементе файла с помощью атрибута fx: controller.






    

Обратите внимание на атрибут fx: controller в корневом элементе (элемент VBox). Этот атрибут содержит имя класса контроллера. Экземпляр этого класса создается при загрузке файла FXML. Чтобы это работало, класс контроллера должен иметь конструктор без аргументов.

Установка экземпляра контроллера на FXMLLoader

При установке экземпляра контроллера на FXMLLoader вы должны сначала создать экземпляр класса контроллера, а затем установить этот экземпляр на FXMLLoader.

MyFxmlController controller = new MyFxmlController();

FXMLLoader loader = new FXMLLoader();
loader.setController(controller);

Привязка компонентов к полям контроллера

Вы можете связать компоненты в файле FXML с полями в классе контроллера. Чтобы это сделать, необходимо дать элементу для компонента атрибут fx: id, который имеет имя поля контроллера, чтобы связать его как значение. Вот пример:

public class MyFxmlController {

    public Label label1 = null;

}

А вот файл FXML с элементом Label, связанным с полем label1 класса контроллера:

 
    

Обратите внимание, что значение атрибута fx: id имеет значение label1, которое совпадает с именем поля в классе контроллера, с которым оно должно быть связано.

Методы ссылки в контроллере

Можно ссылаться на методы в экземпляре контроллера из FXML. Например, вы можете связать события компонента JavaFX GUI с методами контроллера:



    

В этом примере связывается событие onAction Button с методом buttonClicked в классе контроллера. Вот как должен выглядеть класс контроллера, чтобы включить привязку события:

import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class MyFxmlController {

    @FXML
    public void buttonClicked(Event e){
        System.out.println("Button clicked");
    }

}

Обратите внимание на аннотацию @FXML над методом buttonClicked. Она помечает метод как цель для привязки для FXML. Также обратите внимание, что имя buttonClicked упоминается в файле FXML.

Получение экземпляра контроллера из FXMLLoader

Как только экземпляр FXMLLoader загрузит документ, вы можете получить ссылку на экземпляр контроллера через метод getController() FXMLLoader. Вот пример:

MyFxmlController controllerRef = loader.getController();

Оцените статью