Введение в JavaFx
1. Вступление
JavaFX - это библиотека для создания многофункциональных клиентских приложений на Java. It provides an API for designing GUI applications, которые работают почти на всех устройствах с поддержкой Java.
В этом руководстве мы сосредоточимся и рассмотрим некоторые его ключевые возможности и функции.
2. JavaFX API
В Java 8, 9 и 10 не требуется никаких дополнительных настроек для начала работы с библиотекой JavaFX. Проект будет удален из JDK, начиная с JDK 11.
2.1. Архитектура
JavaFX uses hardware accelerated graphics pipeline for the rendering, known as Prism. Более того, чтобы полностью ускорить использование графики, он использует программный или аппаратный механизм рендеринга за счет внутреннего использованияDirectX иOpenGL.
JavaFX has a platform dependent Glass windowing toolkit layer to connect to the native operating system. Он использует очередь событий операционной системы для планирования использования потоков. Кроме того, он асинхронно обрабатывает окна, события, таймеры.
МеханизмыMedia иWeb обеспечивают воспроизведение мультимедиа и поддержку HTML / CSS.
Давайте посмотрим, как выглядитmain structure приложения JavaFX:
Здесь мы видим два основных контейнера:
-
Stage is the main container and the entry point of the application. Он представляет главное окно и передается в качестве аргумента методаstart().
-
Scene - это контейнер для хранения элементов пользовательского интерфейса, таких как представления изображений, кнопки, сетки, текстовые поля.
Scene можно заменить или заменить на другойScene. Он представляет собой граф иерархических объектов, который известен как графикScene. Каждый элемент в этой иерархии называется узлом. У одного узла есть свой идентификатор, стиль, эффекты, обработчики событий, состояние.
Кроме того,Scene также содержит контейнеры макета, изображения, мультимедиа.
2.2. Потоки
На системном уровнеthe JVM creates separate threads for running and rendering the application:
-
Поток рендерингаPrism - отвечает за рендерингScene Graph отдельно.
-
Поток приложения - это основной поток любого приложения JavaFX. Все живые узлы и компоненты прикреплены к этой теме.
2.3. Жизненный цикл
Классjavafx.application.Application имеет следующие методы жизненного цикла:
-
init() – is called after the application instance is created. На данный момент JavaFX API еще не готов, поэтому мы не можем создавать здесь графические компоненты.
-
start(Stage stage) - здесь создаются все графические компоненты. Такжеthe main thread for the graphical activities starts here.
-
stop() - вызывается перед завершением работы приложения; например, когда пользователь закрывает главное окно. Полезно переопределить этот метод для некоторой очистки перед завершением работы приложения.
Статический методlaunch() запускает приложение JavaFX.
2.4. FXML
JavaFX использует специальный язык разметки FXML для создания интерфейсов просмотра.
Это обеспечивает структуру на основе XML для отделения представления от бизнес-логики. Здесь больше подходит XML, так как он может вполне естественно представлять иерархиюScene Graph.
Наконец, чтобы загрузить файл.fxml, мы используем классFXMLLoader, который приводит к графу объектов иерархии сцены.
3. Начиная
Чтобы стать практичным, иlet’s build a small application that allows searching through a list of people.
Во-первых, давайте добавим класс моделиPerson для представления нашей области:
public class Person {
private SimpleIntegerProperty id;
private SimpleStringProperty name;
private SimpleBooleanProperty isEmployed;
// getters, setters
}
Обратите внимание, как для завершения значенийint, String иboolean мы используем классыSimpleIntegerProperty, SimpleStringProperty, SimpleBooleanProperty в пакетеjavafx.beans.property.
Затем давайте создадим классMain, который расширяет абстрактный классApplication:
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(
Main.class.getResource("/SearchController.fxml"));
AnchorPane page = (AnchorPane) loader.load();
Scene scene = new Scene(page);
primaryStage.setTitle("Title goes here");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Наш основной класс переопределяет методstart(), который является точкой входа для программы.
ЗатемFXMLLoader загружает иерархию графа объектов изSearchController.fxml вAnchorPane.
После запуска новогоScene мы устанавливаем его на первичныйStage. Мы также устанавливаем заголовок для нашего окна иshow() его.
Обратите внимание, что полезно включить методmain(), чтобы иметь возможность запускать файл JAR безJavaFX Launcher.
3.1. Просмотр FXML
Давайте теперь углубимся в XML-файлSearchController.
Для нашего поискового приложения мы добавим текстовое поле для ввода ключевого слова и кнопку поиска:
AnchorPane здесь является корневым контейнером и первым узлом иерархии графа. При изменении размера окна, оно будет перемещать дочерний элемент в его точку привязки. The fx: controller attribute wires the Java class with the markup.
Есть несколько других встроенных макетов:
-
BorderPane - делит макет на пять разделов: верхний, правый, нижний, левый, центральный
-
HBox – расположить дочерние компоненты на горизонтальной панели
-
VBox – дочерние узлы расположены в вертикальном столбце
-
GridPane - полезно для создания сетки со строками и столбцами
В нашем примере внутри горизонтальной панелиHBox мы использовалиLabel для размещения текста,TextField для ввода иButton. С помощьюfx: id мы отмечаем элементы, чтобы мы могли использовать их позже в коде Java.
Затем, чтобы сопоставить их с полями Java - мы используем аннотацию@FXML:
public class SearchController {
@FXML
private TextField searchField;
@FXML
private Button searchButton;
@FXML
private void initialize() {
// search panel
searchButton.setText("Search");
searchButton.setOnAction(event -> loadData());
searchButton.setStyle("-fx-background-color: #457ecd; -fx-text-fill: #ffffff;");
}
}
After populating the @FXML annotated fields, initialize() will be called automatically. Здесь мы можем выполнять дальнейшие действия над компонентами пользовательского интерфейса - например, регистрировать прослушиватели событий, добавлять стиль или изменять свойство текста.
Наконец, вся эта логика, описанная здесь, создаст следующее окно:
4. Binding APIс
Теперь, когда визуальные аспекты обработаны, давайте приступим к связыванию данных.
API привязки предоставляет некоторые интерфейсы, которые уведомляют объекты, когда происходит изменение значения другого объекта.
Мы можем привязать значение с помощью методаbind() или путем добавления слушателей.
Однонаправленная привязка обеспечивает привязку только для одного направления:
searchLabel.textProperty().bind(searchField.textProperty());
Здесь любое изменение в поле поиска приведет к обновлению текстового значения метки.
Для сравнения, двунаправленная привязка синхронизирует значения двух свойств в обоих направлениях.
Альтернативный способ привязки полей:ChangeListeners:
searchField.textProperty().addListener((observable, oldValue, newValue) -> {
searchLabel.setText(newValue);
});
ИнтерфейсObservable позволяет наблюдать за изменениями стоимости объекта.
Чтобы проиллюстрировать это, наиболее часто используемой реализацией является интерфейсjavafx.collections.ObservableList<T>:
ObservableList masterData = FXCollections.observableArrayList();
Здесь любое изменение модели, такое как вставка, обновление или удаление элементов, немедленно уведомит элементы управления пользовательского интерфейса.
5. совпадение
Working with the UI components in a scene graph isn’t thread-safe, as it’s accessed only from the Application thread. Пакетjavafx.concurrent здесь, чтобы помочь с многопоточностью.
Давайте посмотрим, как мы можем выполнять поиск данных в фоновом потоке:
Task> task = new Task>() {
@Override
protected ObservableList call() throws Exception {
updateMessage("Loading data");
return FXCollections.observableArrayList(masterData
.stream()
.filter(value -> value.getName().toLowerCase().contains(searchText))
.collect(Collectors.toList()));
}
};
Здесь мы создаем объект одноразовой задачиjavafx.concurrent.Task и переопределяем методcall().
The call() method runs entirely on the background thread and returns the result to the Application thread. Это означает, что любые манипуляции с компонентами пользовательского интерфейса внутри этого метода вызовут исключение времени выполнения.
ОднакоupdateProgress(), updateMessage() можно вызывать для обновления элементов потока приложения. Когда состояние задачи переходит в состояние SUCCEEDED, обработчик событийonSucceeded() вызывается из потока приложения:
task.setOnSucceeded(event -> {
masterData = task.getValue();
// update other UI components
});
Task - этоRunnable, поэтому для его запуска нам нужно просто запустить новыйThread с параметромtask:
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
ФлагsetDaemon(true) указывает, что поток завершится после завершения работы.
6. Обработка событий
Мы можем описать событие как действие, которое может быть интересным для приложения.
Например, такие действия пользователя, как щелчки мыши, нажатия клавиш, изменение размера окна, обрабатываются или уведомляются классомjavafx.event.Event или любым из его подклассов.
Также мы выделяем три типа событий:
-
InputEvent - все типы клавиш и действий мыши, напримерKEY_PRESSED, KEY_TYPED, KEY_RELEASED илиMOUSE_PRESSES, MOUSE_RELEASED
-
ActionEvent - представляет собой множество действий, таких как выстрел изButton или завершениеKeyFrame
-
WindowEvent -WINDOW_SHOWING, WINDOW_SHOWN
Для демонстрации приведенный ниже фрагмент кода перехватывает событие нажатия клавишиEnter надsearchField:
searchField.setOnKeyPressed(event -> {
if (event.getCode().equals(KeyCode.ENTER)) {
//search and load some data
}
});
7. Стиль
Мы можем изменить пользовательский интерфейс приложения JavaFX, применив к нему индивидуальный дизайн.
По умолчанию JavaFX используетmodena.css в качестве ресурса CSS для всего приложения. Это частьjfxrt.jar.
Чтобы переопределить стиль по умолчанию, мы можем добавить таблицу стилей к сцене:
scene.getStylesheets().add("/search.css");
Мы также можем использовать встроенный стиль; например, чтобы установить свойство стиля для определенного узла:
searchButton.setStyle("-fx-background-color: slateblue; -fx-text-fill: white;");
8. Заключение
Этот краткий обзор охватывает основы API JavaFX. Мы прошли внутреннюю структуру и представили ключевые возможности ее архитектуры, жизненного цикла и компонентов.
В результате мы узнали и теперь можем создать простое приложение с графическим интерфейсом.
И, как всегда, доступен полный исходный код учебникаover on GitHub.