Example Task

Create a JavaFX application called “Registration Form” that contains:

  • a username field (TextField);
  • a password field (PasswordField);
  • a “Register” button (Button);
  • a status text field (Label).

The application should:

  • validate the data in real time;
  • enable the button only when the data is valid.
1. Implementation Using the Imperative Model 2. Implementation Using the Reactive Model
1.1 Application Structure

ps-project/
└─ src/
   └─ main/
      ├─ java/
      │  └─ bg/
      │     └─ tu_varna/
      │        └─ sit/
      │           └─ ps/
      │              └─ lab4/
      │                 └─ task1/
      │                    ├─ RegistrationApplication.java
      │                    ├─ Launcher.java
      │                    └─ controller/
      │                       └─ RegistrationController.java
      └─ resources/
         └─ bg/
            └─ tu_varna/
               └─ sit/
                  └─ ps/
                     └─ lab4/
                        └─ task1/
                           └─ registration-view.fxml
            

ps-project/
└─ src/
   └─ main/
      ├─ java/
      │  └─ bg/
      │     └─ tu_varna/
      │        └─ sit/
      │           └─ ps/
      │              └─ lab4/
      │                 └─ task2/
      │                    ├─ RegistrationApplication.java
      │                    ├─ Launcher.java
      │                    └─ controller/
      │                       └─ RegistrationController.java
      └─ resources/
         └─ bg/
            └─ tu_varna/
               └─ sit/
                  └─ ps/
                     └─ lab4/
                        └─ task2/
                           └─ registration-view.fxml
            
3. Controller
In the imperative approach:
  • the logic is executed only when an event occurs;
  • the validation is performed manually;
  • there is no automatic reaction when the data changes.
In the reactive approach:
  • JavaFX Properties are used;
  • reacts in real time;
  • automatically manages the UI through binding.
package controller;

import javafx.fxml.FXML;
import javafx.scene.control.*;

public class RegistrationController {

    @FXML
    private TextField usernameField;

    @FXML
    private PasswordField passwordField;

    @FXML
    private Button registerButton;

    @FXML
    private Label statusLabel;

    @FXML
    public void initialize() {

        registerButton.setOnAction(e -> {
            String username = usernameField.getText();
            String password = passwordField.getText();

            if (username.length() >= 4 && password.length() >= 6) {
                statusLabel.setText("The data is valid.");
            } else {
                statusLabel.setText("Invalid data");
            }
        });
    }
}
package controller;

import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.event.ActionEvent;

public class RegistrationController {

    @FXML
    private TextField usernameField;

    @FXML
    private PasswordField passwordField;

    @FXML
    private Button registerButton;

    @FXML
    private Label statusLabel;

    // JavaFX Properties (reactive state)
    private final BooleanProperty validUsername =
            new SimpleBooleanProperty(false);

    private final BooleanProperty validPassword =
            new SimpleBooleanProperty(false);

    @FXML
    public void initialize() {

        /* ===== Observer (ChangeListener + addListener) ===== */
        usernameField.textProperty().addListener(
            (obs, oldVal, newVal) ->
                validUsername.set(newVal.length() >= 4)
        );

        passwordField.textProperty().addListener(
            (obs, oldVal, newVal) ->
                validPassword.set(newVal.length() >= 6)
        );

        /* ===== Binding ===== */
        BooleanBinding formInvalid =
                validUsername.not().or(validPassword.not());

        registerButton.disableProperty().bind(formInvalid);

        /* ===== Observer върху Binding ===== */
        formInvalid.addListener((obs, oldVal, newVal) -> {
            if (newVal) {
                statusLabel.setText("Invalid data");
            } else {
                statusLabel.setText("The data is valid");
            }
        });

        /* ===== EventHandler ===== */
        registerButton.setOnAction(this::handleRegister);

        /* ===== addEventHandler ===== */
        registerButton.addEventHandler(
            ActionEvent.ACTION,
            e -> System.out.println("Processed ActionEvent")
        );
    }

    private void handleRegister(ActionEvent event) {
        statusLabel.setText("Registration successful!");
    }
}
  • Validation occurs only when the button is pressed
  • The UI does not react while typing
  • Automatic synchronization is missing
  • This approach is typical of the imperative model
  • Validation occurs in real time
  • The UI reacts to every change
  • There is automatic synchronization through binding
  • This approach is typical of the reactive model
4. FXML file – user interface – registration-view.fxml
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.VBox?>

<VBox spacing="10" alignment="CENTER"
      xmlns:fx="http://javafx.com/fxml"
      fx:controller="bg.tu_varna.sit.ps.lab4.task1.controller.RegistrationController">

    <TextField fx:id="usernameField"
               promptText="Username"/>

    <PasswordField fx:id="passwordField"
                   promptText="Password"/>

    <Button fx:id="registerButton"
            text="Registration"/>

    <Label fx:id="statusLabel"
           text="Enter data"/>

</VBox>
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.VBox?>

<VBox spacing="10" alignment="CENTER"
      xmlns:fx="http://javafx.com/fxml"
      fx:controller="bg.tu_varna.sit.ps.lab4.task2.controller.RegistrationController">

    <TextField fx:id="usernameField"
               promptText="Username"/>

    <PasswordField fx:id="passwordField"
                   promptText="Password"/>

    <Button fx:id="registerButton"
            text="Registration"/>

    <Label fx:id="statusLabel"
           text="Enter data"/>

</VBox>
  • FXML describes only the UI, without logic.
  • fx:id provides a connection to the controller
5. Application class
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class RegistrationApplication extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        
        FXMLLoader loader = new FXMLLoader(
            RegistrationApplication.class
            .getResource("registration-view.fxml")
        );

        Parent root = loader.load();

        Scene scene = new Scene(root, 300, 200);

        stage.setTitle("JavaFX FXML imperative Example");
        stage.setScene(scene);
        stage.show();
    }
}
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class RegistrationApplication extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        
        FXMLLoader loader = new FXMLLoader(
            RegistrationApplication.class
            .getResource("registration-view.fxml")
        );

        Parent root = loader.load();

        Scene scene = new Scene(root, 300, 200);

        stage.setTitle("JavaFX FXML Reactive Example");
        stage.setScene(scene);
        stage.show();
    }
}
6. Launcher class

  import javafx.application.Application;

  public class Launcher {
      public static void main(String[] args) {
          Application.launch(RegistrationApplication.class, args);
      }
  }

6. Comparison of FXML: Imperative vs Reactive

Criterion Imperative Reactive
Reaction during input No Yes
Properties No Yes
Binding No Yes
Listeners Limited Active
Maintenance More difficult Easier

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