Лабораторно упражнение 3

JavaFX Properties, Imperative и Reactive модел и механизми за наблюдение и обработка на събития

Разработката на графични потребителски интерфейси изисква постоянна синхронизация между данните на приложението и визуалните компоненти. В ранните UI технологии тази синхронизация се реализира чрез т.нар. imperative модел, при който разработчикът ръчно управлява всяка промяна в интерфейса.

С нарастване на сложността на приложенията този подход води до труден за поддръжка код и висока вероятност от грешки. В отговор на тези проблеми JavaFX въвежда reactive модел, който автоматизира реакцията на интерфейса при промени в данните и действията на потребителя.

1. Imperative модел при разработка на UI

1.1 Същност на imperative модела

Imperative моделът представлява подход, при който разработчикът изрично описва последователността от действия, които трябва да се изпълнят при всяка промяна в данните или събитие от потребителя.

Основни характеристики:

  • UI се обновява ръчно;
  • логиката и интерфейсът са силно свързани;
  • всяка промяна изисква допълнителен код.

1.2 Пример за imperative подход

button.setOnAction(e -> {
    String text = textField.getText();
    label.setText(text);
});

В този пример:

разработчикът ръчно извлича стойността;

ръчно обновява UI компонента;

кодът се изпълнява само при конкретно събитие.

Ако стойността на textField се промени по друг начин, label няма да бъде обновен.

1.3 Недостатъци на imperative модела

  • необходимост от повторение на логика;
  • риск от пропуснати обновявания;
  • трудна поддръжка при сложни зависимости;
  • по-ниска четимост на кода.

Тези ограничения мотивират въвеждането на реактивен подход.

2. Reactive модел в JavaFX

Reactive моделът в JavaFX представлява архитектурен подход, при който потребителският интерфейс реагира автоматично на промени в състоянието на приложението. Основната идея е данните да бъдат централен елемент, а UI компонентите да бъдат техни наблюдатели.

2.1 Пример за reactive подход

label.textProperty().bind(textField.textProperty());

След създаването на тази връзка:

  • label се обновява автоматично;
  • няма нужда от допълнителен код;
  • всички промени се отразяват в реално време.

3. Сравнение между imperative и reactive модел

Критерий Imperative Reactive (JavaFX)
Обновяване на UI Ръчно Автоматично
Свързаност Висока Ниска
Код Повече По-малко
Грешки По-вероятни По-малко
Поддръжка Трудна Лесна

4. JavaFX Properties

За реализацията на реактивния модел JavaFX използва Properties – наблюдаеми контейнери за данни. Те съхраняват стойност и уведомяват регистрираните наблюдатели при всяка промяна.

Често използвани типове:

  • StringProperty
  • IntegerProperty
  • BooleanProperty

Properties са ключови за автоматичното обновяване на интерфейса.

5. Observer Pattern и ChangeListener

След като свойствата могат да се променят динамично, JavaFX използва Observer design pattern, при който:

Property е наблюдаваният обект;

ChangeListener е наблюдателят.

Пример:

textField.textProperty().addListener(
    (obs, oldValue, newValue) -> {
        System.out.println(oldValue + " -> " + newValue);
    }
);

6. addListener в JavaFX

Методът addListener() регистрира слушател към дадено Property и позволява реакция при всяка промяна.

Слушателите могат да бъдат:

  • ChangeListener
  • InvalidationListener

Този механизъм осигурява гъвкав контрол върху реакцията на системата.

Binding в JavaFX

Binding автоматизира observer механизма и премахва необходимостта от ръчно управление на listener-и.

Пример:

button.disableProperty().bind(textField.textProperty().isEmpty());

В този случай бутонът автоматично се деактивира при празно поле.

8. Event Handling в JavaFX

Докато Property реагира на промени в състоянието, Event Handling обработва действия на потребителя.

Пример:

button.setOnAction(e -> {
    System.out.println("Бутонът е натиснат");
});

9. addEventHandler в JavaFX

addEventHandler() предоставя разширен контрол и позволява добавянето на множество обработчици за едно събитие.

Пример:

button.addEventHandler(ActionEvent.ACTION, e -> {
    System.out.println("Action обработен");
});

Imperative моделът поставя основата за разработка на UI, но при по-сложни приложения става труден за поддръжка. Reactive моделът в JavaFX решава тези проблеми чрез Properties, listener-и, binding и event handling, осигурявайки автоматична синхронизация между данните и интерфейса.

10. Управление на JavaFX приложения

Controller е клас, който обработва действията на потребителя (кликове, въвеждане на данни), чете и валидира данните от FXML файловете, обновява сцените чрез JavaFX механизми (binding, setText, disable и др.)

В JavaFX Controller е Java клас, който се свързва с FXML файла и управлява поведението на потребителския интерфейс.

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

Във FXML файл контролерът се дефинира и използва чрез няколко ключови елемента.

fx:controller атрибута свързва FXML файла с конкретен Java Controller клас, Указва на FXMLLoader кой клас да създаде при зареждане.

<GridPane fx:controller="controller.LoginController"
          xmlns:fx="http://javafx.com/fxml">

fx:id атрибута е уникален идентификатор на UI елемент във FXML, който позволява достъп до компонента от контролера. Името на променливата в контролера трябва да съвпада с fx:id

@FXML
private TextField usernameField;

@FXML анотация маркира полета и методи, които се свързват с FXML, позволява инжектиране на UI елементи от FXML

Event handlers - FXML атрибутите onAction, onMouseClicked, и др. свързват UI събитие с метод в Controller. Метода трябва да съществува в контролера, да е маркиран с @FXML, да е void

<Button text="Вход" onAction="#onLogin"/>
@FXML
private void onLogin() {
    // логика при натискане на бутона
}

Метод initialize() се извиква автоматично след зареждане на FXML. Използва се при инициялизация на binding, listeners и първоначално състояние на UI

@FXML
public void initialize() {
    // код за инициализация
}

Table of contents


This site uses Just the Docs, a documentation theme for Jekyll.