Часть 1: Scene Builder
Нам нужно указать среде разработки Eclipse использовать JDK 8, а также задать путь к приложению Scene Builder:
- Откройте настройки среды разработки Eclipse и перейдите к пункту Java | Installed JREs.
- Нажмите Add…, выберите Standart VM и укажите путь к установленной JDK 8.
- Уберите другие добавленные JDK и 8-я JDK будет использоваться по умолчанию.
- Перейдите к пункту Java | Compiler. Установите значение настройки Compiler compliance level в 1.8.
- Перейдите к пункту JavaFX и укажите путь к исполняемому файлу приложения Scene Builder.
Полезные ссылки
Возможно, вы захотите добавить закладки на следующие ссылки:
- Java 8 API — документация по стандартным классам Java;
- JavaFX 8 API — документация по классам JavaFX;
- ControlsFX API — документация по дополнительным элементам JavaFX из проекта ControlsFX;
- Oracle’s JavaFX Tutorials — официальный учебник по JavaFX от Oracle.
Ну что же, давайте приступим к изучению!
Создание нового проекта JavaFX
В приложение Eclipse (с уже установленным e(fx)clipse) в меню выберите пункт File | New | Other…, и затем выберите JavaFX Project.
Укажите имя проекта (наше будет называться AddressApp) и нажмите Finish.
Если Eclipse автоматически создало какие-то начальные файлы и пакеты, то удалите их.
Создание структуры пакетов
С самого начала мы будем следовать хорошим принципам проектирования ПО. Один из них — это шаблон проектирования Модель-Представление-Контроллер (MVC). Опираясь на этот шаблон мы разобьём код нашего приложения на три части и создадим для каждой из них свой пакет (правый клик на папке src, New… | Package):
- ch.makery.address — содержит большинство классов-контроллеров (Controller) (= классов бизнес логики);
- ch.makery.address.model — содержит классы Моделей (Model);
- ch.makery.address.view — содержит Представления (View).
Заметка: Внутри пакета view также будут лежать некоторые классы-контроллеры, которые непосредственно связаны с конкретными представлениями. Давайте называть их контроллеры-представлений (view-controllers).
Создание файла разметки FXML
Есть два пути создания пользовательского интерфейса: либо использовать файл разметки FXML, либо программировать всё на Java. В большинстве своём мы будем использовать XML (.fxml). Я считаю, что этот способ больше подходит для отделения контроллеров от представлений. В дальнейшем мы сможем использовать Scene Builder для визуального редактирования наших XML-файлов. А это значит, что мы не будем напрямую работать с XML.
Кликните на пакете view правой кнопкой мышки и создайте новый документ FXML с названием PersonOverview .
Проектировка визуального интерфейса в Scene Builder
Примечание: Если по какой-то причине ваш код не заработает, то скачайте исходники к этой части учебника и возьмите файл fxml оттуда.
Откройте только что созданный fxml-документ в приложении Scene Builder — клик правой кнопкой мышки по файлу PersonOverview.fxml , Open with SceneBuilder. На вкладке Hierarchy должен находиться единственный компонент AnchorPane.
(Если Scene Builder не запустился, то открываем пункт меню Window | Preferences | JavaFX и настраиваем верный путь к исполняемому файлу установленного приложения Scene Builder).
- На вкладке Hierarchy выберите компонент AnchorPane, и справа, на вкладке Layout установите значение характеристикам Pref Width и Pref Height — 600 и 300 соответственно.
- На вкладке Hierarchy в компонент AnchorPane добавьте новый компонент SplitPane (horizontal). Кликните по нему правой кнопкой мыши и выберите Fit to Parent.
- Теперь, в левую часть компонента SplitPane со вкладки Controls перетащите компонент TableView. Выделите его целиком (а не отдельный столбец) и проставьте отступы от краёв так, как показано на рисунке. Внутри компонента AnchorPane всегда можно проставить отступы от четырёх границ рамки (дополнительная информация о разметках).
- Чтобы увидеть, правильно ли отображается созданное окно, выполните пункт меню Preview | Show Preview in Window. Попробуйте поменять размер окна. Добавленная таблица должна изменятся вместе с окном, так как она прикреплена к границам окна.
- В таблице измените заголовки колонок (вкладка Properties компонента TableColumn) на “First Name” и “Last Name”.
- Выберите компонент TableView и во вкладке Properties измените значение Column Resize Policy на constrained-resize. Выбор этой характеристики гарантирует, что колонки таблицы всегда будут занимать всё доступное пространство.
- В правую часть компонента SplitPane перетащите компонент Label и измените его текст на “Person Details” (подсказка: используйте поиск для скорейшего нахождения компонентов). Используя привязки к границам (вкладка Layout) скорректируйте его положение.
- На правую панель SplitPane добавьте компонент GridPane и так же настройте привязки к границам, как показано на рисунке.
- Приведите своё окно в соответствие с тем, что показано на рисунке, добавляя компоненты Label внутрь ячеек компонента GridPane.
Примечание: для того, чтобы добавить новый ряд в компонент GridPane, выберите существующий номер ряда (он окрасится жёлтым), кликните правой кнопкой мышки на номере ряда и выберите пункт “Add Row Above” или “Add Row Below”. - Внизу добавьте ButtonBar, а в него три кнопки Button. Теперь установите привязки к границам (правой и нижней), чтобы ButtonBar всегда находилась справа.
Так как панель ButtonBar доступна только с JavaFX 8, и её поддержка в Scene Builder на данный момент несколько хромает, то имеется альтернативный способ. Добавьте три компонента Button в правую часть так, как показано на предыдущем рисунке. Выделите их всех вместе (Shift + клик), кликните по ним правой кнопкой мышки и выберите пункт Wrap In | HBox. Это действие их сгруппирует. Вы можете задать расстояние (Spacing) между компонентами во вкладке Properties компонента HBox. Также установите привязки к границам (правой и нижней).
- Если всё сделано правильно, то у нас должно получится что-то похожее на рисунок ниже. Используйте пункт меню Preview, чтобы протестировать созданное окно и его реакцию на изменение размеров.
Создание основного приложения
Нам необходимо создать ещё один файл fxml-разметки, в котором будет компонент полосы меню. Этот файл будет служить обёрткой для только что созданного PersonOverview.fxml .
- В пакете view создайте другой fxml-документ, и назовите его RootLayout.fxml . На этот раз в качестве корневого элемента выберите BorderPane.
- Откройте файл RootLayout.fxml в приложении Scene Builder.
- Установите предпочитаемое значение ширины и высоты компонента: 600 и 400 соответственно.
- В верхний слот компонента BorderPane добавьте компонент MenuBar. Функциональность меню мы будем реализовывать в последующих уроках.
Основной класс приложения JavaFX
Теперь нам надо создать основной класс Java, который будет запускать наше приложение с RootLayout.fxml и добавлять в его центральную область PersonOverview.fxml .
- Кликните правой кнопкой мыши по нашему проекту, перейдите к пункту New | Other… и выберите JavaFX Main Class.
- Назовите класс MainApp и поместите его в пакет ch.makery.address (примечание: это пакет является родительским для view и model ).
Созданный класс MainApp.java расширяет класс Application и содержит два метода. Это базовая структура, которая необходима для запуска приложения JavaFX. Нам интересен метод start(Stage primaryStage) . Он автоматически вызывается при вызове метода launch(. ) из метода main .
Как можно заметить, метод start(. ) в качестве параметра принимает экземпляр класса Stage . На следующем рисунке представлена структура любого приложения JavaFX:
Источник изображения: http://www.oracle.com/
Это как театральное представление Stage (театральные подмостки) является основным контейнером, который, как правило, представляет собой обрамлённое окно со стандартными кнопками: закрыть, свернуть, развернуть. Внутрь Stage добавляется сцена Scene , которая может быть заменена другой Scene . Внутрь Scene добавляются стандартные компоненты типа AnchorPane , TextBox и другие.
Для получения более детальной информации о такой компоновке обратитесь к этому руководству: Working with the JavaFX Scene Graph.
Откройте класс MainApp.java и замените его содержимое на это:
package ch.makery.address; import java.io.IOException; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; public class MainApp extends Application < private Stage primaryStage; private BorderPane rootLayout; @Override public void start(Stage primaryStage) < this.primaryStage = primaryStage; this.primaryStage.setTitle("AddressApp"); initRootLayout(); showPersonOverview(); >/** * Инициализирует корневой макет. */ public void initRootLayout() < try < // Загружаем корневой макет из fxml файла. FXMLLoader loader = new FXMLLoader(); loader.setLocation(MainApp.class.getResource("view/RootLayout.fxml")); rootLayout = (BorderPane) loader.load(); // Отображаем сцену, содержащую корневой макет. Scene scene = new Scene(rootLayout); primaryStage.setScene(scene); primaryStage.show(); >catch (IOException e) < e.printStackTrace(); >> /** * Показывает в корневом макете сведения об адресатах. */ public void showPersonOverview() < try < // Загружаем сведения об адресатах. FXMLLoader loader = new FXMLLoader(); loader.setLocation(MainApp.class.getResource("view/PersonOverview.fxml")); AnchorPane personOverview = (AnchorPane) loader.load(); // Помещаем сведения об адресатах в центр корневого макета. rootLayout.setCenter(personOverview); >catch (IOException e) < e.printStackTrace(); >> /** * Возвращает главную сцену. * @return */ public Stage getPrimaryStage() < return primaryStage; >public static void main(String[] args) < launch(args); >>
Комментарии могут служить подсказками того, что и как делается.
Запустив приложение мы должны увидеть что-то похожее на то, что изображено на рисунке в начале этой статьи.
Часто встречающиеся проблемы
Если JavaFX не может найти указанный fxml -файл, то вы получите следующее сообщение об ошибке:
java.lang.IllegalStateException: Location is not set.
Для решения этой проблемы внимательно проверьте правильность указания пути к файлам fxml и правильность написания его названия.
Если и после этого не удастся запустить приложение, то скачайте исходники к этой части и запустить их.
Что дальше?
Во 2-й части учебника мы добавим в наше приложение некоторые данные и функциональность.
Вам могут быть интересны также некоторые другие статьи на английском языке:
- JavaFX Dialogs (official)
- JavaFX Date Picker
- JavaFX Event Handling Examples
- JavaFX TableView Sorting and Filtering
- JavaFX TableView Cell Renderer
Subscribe to receive updates by Email.
Configure JavaFX Scene Builder
IntelliJ IDEA allows you to open .fxml files in JavaFX Scene Builder right from the IDE after you specify the path to the Scene Builder application in the settings.
Configure Scene Builder in settings
- Download and install the latest version of Scene Builder.
- In the Settings dialog ( Control+Alt+S ), select Languages & Frameworks | JavaFX .
- Click in the Path to SceneBuilder field.
- In the dialog that opens, select the Scene Builder application (executable file) on your computer and click OK .
- Click Apply to save the changes and close the dialog.
Download Scene Builder from the IDE
If your project doesn’t have JavaFX Scene Builder, you will see a notification on the Scene Builder tab for .fxml files.
- Click Download Scene Builder Kit in the notification to download and install the tool.
After that you can open .fxml files in Scene Builder right in the editor.
Open files in Scene Builder
When you open an .fxml file in the editor, there are two tabs underneath the editing area: the Text tab is for developing the markup, and the Scene Builder tab is for editing the file in Scene Builder.
- Scene Builder 2.x. and later. If you are using Scene Builder of the version 2.x. and later, the files will be opened in Scene Builder on the Scene Builder tab by default.
- Scene Builder 1.x If you are using Scene Builder of the version 1.x, the Scene Builder tab is empty. In this case, right-click the necessary .fxml file in the Project tool window and select Open In SceneBuilder from the context menu.
Программирование JavaFX: использование SceneBuilder
В прошлой статье мы начали разговор о фреймворке JavaFX, который позволяет создавать интерфейсы, оставаясь в рамках знакомой вам среды разработки (не нужно изучать веб-технологии). В этот раз мы поговорим о средстве упрощения и ускорения разработки интерфейсов — SceneBuilder.
Несмотря на то что интерфейсы возможно создавать только в коде, и в прошлый раз мы ознакомились с целым семейством классов, которые позволяют это делать, вряд ли кто-то будет спорить с тем фактом, что графическое создание по принципу Drag&Drop является более удобным и быстрым. К тому же (со временем) я всё чаще прихожу к пониманию того, что глубокое знание того, что происходит под капотом тех или иных технологий, должно дополняться ещё и средствами ускорения разработки. Так как время — это наше всё. Итак.
Установка SceneBuilder
Для начала вам необходимо пройти по ссылке и скачать SceneBuilder.
После установки и запуска у вас появится вот такое окно, в котором вы для примера, можете щёлкнуть на вкладку Empty, что приведёт к созданию пустого приложения без какого-либо содержимого:
Вкратце можно сказать, что весь интерфейс программы разделён на три части: в левой части находится библиотека элементов, которую можно перетаскивать в серединную часть. Правая часть интерфейса предназначена для настройки атрибутов конкретного выбранного элемента (хранящегося в левой части):
Например, давайте перетащим из левой части контейнер Pane и поместим в него кнопку Button. При нажатии на эту кнопку мы видим, что в правой части экрана, появилось большое количество свойств этой кнопки, которые могут быть настроены:
Если мы сейчас сохраним это приложение и попытаемся его открыть, например, с помощью блокнота, то увидим, что в результате создания этого приложения у нас сгенерировался так называемый fxml-код.
Именно это и является целью визуального средства разработки SceneBuilder: удобное и быстрое генерирование кода визуального интерфейса.
Однако мы ведь работаем не только над интерфейсом — он должен быть связан с выполняющимся кодом. Воспользуемся для этого средой разработки IntelljIDEA.
Для начала вам необходимо перейти в раздел настроек, нажав сочетание кнопок Ctrl+Alt+S.
Переходим в раздел Plugins-Marketplace и устанавливаем себе плагин JavaFX:
Альтернативой этому методу является скачивание jdk и указывание, где он лежит (для среды разработки).
Для этого мы также идём в настройки, в раздел Path Variables. Там жмём на плюсик и показываем, где у нас лежит скачанная jdk, а заодно придумываем название для этого пути:
Указываем вплоть до папки lib:
Далее мы идём в раздел Run — Edit Configuration и в строке VM options — вписываем следующее (у меня здесь будет моё название, вы же можете назвать путь до библиотеки по-своему, только оно должно совпадать с тем названием пути, который мы уже сконфигурировали ранее):
Это глобальные настройки, которые будут применяться ко всем новым создаваемым проектам (таким образом, мы просто упростили себе жизнь, если бы мы этого не сделали, нам пришлось бы вводить эти настройки каждый раз заново, в разделе File-Project Structure).
Далее нам необходимо показать среде разработки, где у нас лежит установленная программа SceneBuilder (путь до exe-шника).
Для этого опять жмём Ctrl+ Alt + S, идём в раздел Languages&Frameworks — JavaFX и показываем полный путь до программы:
Для чего вообще нужно было сделать последнюю манипуляцию: всё это для того, чтобы мы могли работать с этой программой прямо внутри среды разработки.
Первое приложение
Теперь, когда у нас всё готово, мы можем попробовать создать своё первое приложение с использованием этого средства разработки GUI.
Для этого мы проходим по пути: File-New-Project и выбираем JavaFX Application:
Далее мы вписываем имя проекта и нажимаем Finish:
Как мы видим в структуре проекта, у нас создаётся три файла, один из которых является запускающим и объединяющим всё (класс Main), второй — выполняющим некие действия (класс Controller), и последний — файл визуальной части, в формате разметки FXML (sample.fxml):
Теперь, если мы кликнем на файл sample.fxml, то увидим, что он, как и положено, открылся в правой части окна. В нижней части окна мы увидим два интересных переключателя: Text и SceneBuilder:
Соответственно, если мы кликнем на SceneBuilder, то произойдёт следующее: наш файл sample.fxml будет открыт в правой части прямо внутри SceneBuilder. Таким образом после всех наших манипуляций — эта программа будет встроена прямо в среду разработки:
Таким образом, мы можем вносить изменения в интерфейс прямо внутри среды разработки!
Правда есть один минус, который заключается в том, что многие из менюшек этой программы мы видеть не будем. Однако всё это легко поправить! Кликаем правой кнопкой мыши по названию файла и выбираем Open In SceneBuilder:
После чего этот файл откроется в абсолютно новом окне, а именно в натуральном интерфейсе SceneBuilder:
Мы можем абсолютно спокойно набросать интерфейс в этой программе, после чего нажать на Ctrl+S (то есть просто сохранить файл) и закрыть интерфейс программы, все необходимые изменения сохранятся и останутся в файле, который отображается в IntellijIDEA.
Итак, создадим простое приложение. Для этого откроем файл sample.fxml в SceneBuilder, перетащим из левой панели в середину, в контейнер Pane, поместим прямо на него кнопку Button и сразу поменяем надпись на кнопке, используя правую панель свойств кнопки:
Далее нам необходимо сделать так, чтобы эта кнопка имела уникальный идентификатор, по которому мы могли бы обращаться к ней в коде. Кроме того, необходимо чтобы она реагировала на клик по ней.
Для этого мы переходим в меню Code: Button и вписываем идентификатор в поле fx:id, а реакцию на нажатие кнопки в поле On Action:
Сохраним получившийся файл и закроем SceneBuilder. Теперь, если мы посмотрим на файл sample.fxml в режиме текста в ItellijIDEA, то мы увидим, что все наши изменения отразились в коде:
Далее переходим в класс Controller и вписываем туда простой код, который будет реагировать на нажатие клавиши. Код позаимствуем вот отсюда и изменим только идентификатор кнопки на свой, а также текст, который будет выводиться на кнопке после нажатия.
То есть, другими словами, кнопка будет реагировать на наши нажатия изменением текста на ней.
После внесённых изменений код контроллера будет выглядеть следующим образом:
package sample; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; public class Controller < @FXML private Button knpka; @FXML private void click(ActionEvent event) < knpka.setText("Вы кликнули!"); >>
Теперь перейдём в главный класс Main, код которого выглядит следующим образом:
package sample; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; public class Main extends Application < @Override public void start(Stage primaryStage) throws Exception< Parent root = FXMLLoader.load(getClass().getResource("sample.fxml")); primaryStage.setTitle("Hello World"); primaryStage.setScene(new Scene(root, 300, 275)); primaryStage.show(); >public static void main(String[] args) < launch(args); >>
и запустим наш тестовый пример. Всё работает:
И напоследок, из удобного: если вы кликните на абсолютно любой пункт правого меню настройки, то у вас сразу в новом окне откроется описание класса, метода, переменной и так далее, что весьма удобно. Эдакий «встроенный Live-справочник»:
Ну вот и всё! Теперь ваше средство визуальной разработки SceneBuilder и среда разработки программ IntellijIDEA представляют собой единое целое, что в процессе работы позволяет легко переключаться с одного на другое.
Напоследок, примечание: на выходе вы получите десктопное скомпилированное приложение (это будет не веб-интерфейс в браузере).
НЛО прилетело и оставило здесь промокод для читателей нашего блога:
— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS .
- Блог компании FirstVDS
- Программирование
- Java
- ООП
Учебник по JavaFX: FXML и SceneBuilder
Как создать графический интерфейс с JavaFX, используя разметку FXML и SceneBuilder.
Все посты в серии о JavaFX:
- Учебник по JavaFX: начало работы
- Учебник по JavaFX: Hello world!
- Учебник по JavaFX: FXML и SceneBuilder
- Учебник по JavaFX: основные макеты
- Учебник по JavaFX: расширенные макеты
- Учебник по JavaFX: CSS стилизация
- JavaFX Weaver: интеграция JavaFX и Spring Boot приложения
Традиционный способ
Просто напоминание — код выглядел так:
@Override public void start(Stage primaryStage) throws Exception < primaryStage.setTitle("Hello world Application"); primaryStage.setWidth(300); primaryStage.setHeight(200); InputStream iconStream = getClass().getResourceAsStream("/icon.png"); Image image = new Image(iconStream); primaryStage.getIcons().add(image); Label helloWorldLabel = new Label("Hello world!"); helloWorldLabel.setAlignment(Pos.CENTER); Scene primaryScene = new Scene(helloWorldLabel); primaryStage.setScene(primaryScene); primaryStage.show(); >
Как видите весь пользовательский интерфейс создан в Java коде.
Это очень простой пример, но по мере усложнения вашего приложения, когда приходится вводить несколько уровней вложенных макетов и множество компонентов, результирующий код может стать очень сложным для понимания. Однако это еще не все — в одном и том же классе присутствует код, который отвечает за структуру, визуальные эффекты и поведение одновременно.
У класса явно нет единой ответственности. Сравните это, например, с веб-интерфейсом, где каждая страница имеет четко разделенные задачи:
- HTML — это структура
- CSS — это визуальные эффекты
- JavaScript — это поведение
Представляем FXML
Очевидно, что иметь весь код в одном месте не очень хорошая идея. Вам нужно как-то структурировать его, чтобы его было легче понять и сделать более управляемым.
В действительности есть много шаблонов дизайна для этого. Как правило, в конечном итоге вы приходите к варианту «Model-View-Whatever» — это что-то вроде «Model View Controller», «Model View Presenter» или «Model View ViewModel».
Можно часами обсуждать плюсы и минусы разных вариантов — давайте не будем делать это здесь. Более важно то, что с JavaFx вы можете использовать любой из них.
Это возможно потому, что в дополнение к процедурной конструкции вашего пользовательского интерфейса вы можете использовать декларативную разметку XML.
Оказывается иерархическая структура XML — это отличный способ описать иерархию компонентов в пользовательском интерфейсе. HTML работает достаточно хорошо, верно?
Формат XML, специфичный для JavaFX, называется FXML. В нем вы можете определить все компоненты приложения и их свойства, а также связать их с контроллером, который отвечает за управление взаимодействиями.
Загрузка FXML файлов
Итак, как мы можем изменить наш метод запуска для работы с FXML?
FXMLLoader loader = new FXMLLoader(); URL xmlUrl = getClass().getResource("/mainScene.fxml"); loader.setLocation(xmlUrl); Parent root = loader.load(); primaryStage.setScene(new Scene(root)); primaryStage.show();
Здесь root представляет корневой компонент вашего пользовательского интерфейса, остальные компоненты вложены в него.
Метод load имеет generic возвращаемое значение, поэтому вы можете указать конкретный тип, а не Parent. Далее, вы получаете доступ к компонентно-ориентированным методам. Однако, это делает ваш код более хрупким. Если вы измените тип корневого компонента в вашем FXML, приложение может перестать работать во время выполнения, но при этом во время компиляции не будет ошибок. Это происходит потому, что теперь есть несоответствие типа, объявленного в вашем FXML и в загрузчике Java FXML.
Создание FXML файла
Теперь мы знаем, как загрузить файл FXML, но нам все еще нужно его создать. Файл должен иметь расширение .fxml. В Maven проекте, вы можете поместить этот файл в папку ресурсов или FXMLLoader может загрузить его с внешнего URL-адреса.
После создадания файла в его первой строке необходимо ввести декларацию XML:
Импорт
Прежде чем добавить отдельные компоненты в файл, необходимо убедиться, что они правильно распознаются. Для этого необходимо добавить операторы импорта. Это очень похоже на импорт в Java классах. Вы можете импортировать отдельные классы или использовать знаки подстановки как обычно. Давайте рассмотрим пример раздела импорта:
Хорошей новостью является то, что вместо добавления всех операторов импорта вручную, ваша IDE должна помочь вам добавить импорт аналогично добавлению их в классы Java.
Добавление компонентов
Теперь пришло время добавить некоторые компоненты. В предыдущей статье мы узнали, что каждая сцена может иметь только один дочерний компонент. Для начала давайте добавим простую метку (label):
Конечно, метка в качестве корневого компонента — это не очень реалистичный пример. Обычно предпочтительнее использовать какой-то макет (layout), который является контейнером для нескольких компонентов и организует их расположение. Мы рассмотрим макеты позже в этой серии, а сейчас давайте просто воспользуемся простым VBox, который размещает свои дочерние элементы вертикально друг над другом.
FX Namespace
Существует пара элементов и атрибутов FXML, которые по умолчанию недоступны. Вам нужно добавить пространство имен (Namespace) FXML, чтобы сделать их доступными. Его необходимо добавить к корневому компоненту:
Теперь можно использовать новые элементы из пространства имен fx. Давайте попробуем добавить уникальные идентификаторы в наши компоненты:
Атрибут fx:id является уникальным идентификатором компонента, который можно использовать для ссылки на компонент из других частей нашего FXML и даже из нашего контроллера.
Скрипты
Наше приложение пока статично. Есть несколько меток и кнопка, но приложение не делает ничего динамического.
Давайте отреагируем на нажатие нашей кнопки и изменим заголовок с «Click me!» на «Click me again!».
Первое, что нужно сделать, это добавить обработчик события onAction для нашей кнопки.
Обратите внимание на fx:id, это идентификатор, который будет использоваться позже для ссылки на кнопку.
Теперь нужно предоставить функцию, которая будет вызвана для обработки события. Ее можно определить внутри тега fx:script. Важно то, что вы можете использовать различные языки для написания скрипта, JavaScript, Groovy или Clojure. Давайте посмотрим пример на JavaScript:
Заметьте, что мы ссылаемся на наш компонент Button с помощью идентификатора mainButton, который был объявлен так:
fx:id = "mainButton"
Также необходимо указать, какой язык сценариев вы используете в файле FXML:
Давайте рассмотрим полный текст примера:
Должен ли я использовать это?
В приведенном выше примере показано, как ссылаться на компоненты с помощью fx:id и как добавить простое поведение с помощью скрипта на JavaScript. Неужели это то, что вы должны на самом деле делать?
Ответ — в большинстве случаев нет. Есть несколько проблем с таким подходом. Причина, по которой введен FXML, была разделение интересов — чтобы отделить структуру и поведение пользовательского интерфейса. В этом скрипте снова вернулось поведение слитное со структурой пользовательского интерфейса. Более того, поскольку мы больше не работаем с кодом Java, а с XML, были утрачены все проверки кода во время компиляции и безопасность типов. Теперь все проблемы в приложении будут обнаружены во время выполнения, а не во время компиляции. Приложение стало очень хрупким и подверженым ошибкам.
Добавление контроллера
Итак, что можно сделать, чтобы получить четкое разделение интересов? Можно связать контроллер с нашим файлом FXML. Контроллер — это Java класс, который отвечает в приложении за обработку поведения и взаимодействия с пользователем. Таким образом можно вернуть безопасность типов и проверки времени компиляции.
Контроллер является POJO, он не должен расширять или реализовывать что-либо, а также не должен иметь никаких специальных аннотаций.
Как можно связать класс контроллера с нашим FXML? По существу, есть два варианта.
На Java
Вы можете создать экземпляр контроллера самостоятельно или использовать любые другие способы создания экземпляра, такие как инъекция зависимости. Затем просто загрузите вашим FXMLLoader.
FXMLLoader loader = new FXMLLoader(); loader.setController(new MainSceneController());
В FXML
Вы можете указать класс вашего контроллера как атрибут fx:controller, который должен находиться в корневом компоненте.
Если вы объявляете свой класс Controller в FXML, он автоматически создается для вас. Этот подход имеет одно ограничение — в контроллере нужно создать конструктор без аргументов, чтобы позволит легко создавать новый экземпляр класса Controller.
Для получения доступа к экземпляру контроллера, созданного автоматически, можно использовать загрузчик FXML:
FXMLLoader loader = new FXMLLoader(); loader.setLocation(getClass().getResource("/mainScene.fxml")); MainSceneController controller = loader.getController();
Вызов методов контроллера
Теперь, когда имеется контроллер, можно удалить скрипт и реализовть логику нажатия кнопок прямо в контроллере:
public class MainSceneController < public void buttonClicked() < System.out.println("Button clicked!"); >>
Следующим шагом является регистрация вызова этого метода в качестве обработчика события onAction нашей кнопки. Чтобы ссылаться на методы из нашего контроллера, нам нужно использовать знак # перед именем метода:
При нажатии на кнопку, она вызывает метод MainSceneController.buttonClicked(). Имейте в виду, что это работает, только если метод объявлен public. Если модификатор доступа более строгий, необходимо аннотировать метод аннотацией @FXML.
@FXML private void buttonClicked()
Внедрение компонентов в контроллер
Пока что мы просто печатаем на консоль. Что если мы снова захотим изменить текст нашей кнопки на «Click me again»? Как мы можем получить ссылки на компоненты в нашем контроллере?
К счастью, это легко. Помните эти атрибуты fx:id?
JavaFX пытается автоматически сопоставить компоненты с fx:id с полями определенным в вашем контроллере с тем же именем.
Предположим, у нас есть кнопка описанная выше с
fx:id="mainButton"
JavaFX пытается внедрить объект кнопки в ваш контроллер в поле с именем mainButton:
public class MainSceneController < //Вот внедренный компонент с fx:id = "mainButton" @FXML private Button mainButton; >
Как и в предыдущих методах, ваши поля должны быть public или аннотированными @FXML.
Теперь, когда у нас есть ссылка на нашу кнопку, можно легко изменить ее текст:
public class MainSceneController < @FXML private Button mainButton; @FXML private void buttonClicked() < mainButton.setText("Click me again!"); >>
Scene Builder
Написание вашей структуры GUI в XML может быть более естественным, чем в Java (особенно если вы знакомы с HTML). Тем не менее, до сих пор это не очень удобно. Хорошей новостью является то, что существует официальный инструмент под названием Scene Builder, который поможет вам в создании пользовательского интерфейса. В двух словах, это графический редактор для вашего графического интерфейса.
В редакторе имеется три основных области:
- В левой части отображаются доступные компоненты, которые можно перетащить в среднюю часть. Она также содержит иерархию всех компонентов в вашем пользовательском интерфейсе, поэтому вы можете легко перемещаться по ней.
- Средняя часть — это ваше приложение, отображаемое на основе вашего файла FXML.
- Справа находится инспектор текущих компонентов. Здесь вы можете редактировать различные свойства выбранного текущего компонента. Любой компонент, выбранный в средней части иерархии, отображается в инспекторе.
Standalone
Scene Builder можно загрузить как отдельное приложение, которое можно использовать для редактирования FXML файлов.
Интеграция с IntelliJ IDEA
В качестве альтернативы, Scene Builder предлагает интеграцию с IDE.
В IntelliJ IDEA вы можете нажать правой кнопкой мыши на любом FXML файле и затем выбрать опцию меню «Открыть» в SceneBuilder.
В качестве альтернативы, IntelliJ IDEA интегрирует SceneBuilder непосредственно в IDE. Если вы откроете файл FXML в IDEA, в нижней части экрана появятся две вкладки
- Текст
- SceneBuilder
В IntelliJ IDEA можто настроить расположение исполняемого файла SceneBuilder:
Settings → Languages & Frameworks → JavaFX → Path to SceneBuilder
Что дальше
В следующем посте из нашей серии будут рассмотрены некоторые основные макеты (layout), которые можно использовать для организации компонентов GUI приложения на JavaFX.