JavaFX Events

Handling user interactions and system events

⚡ What are Events?

JavaFX Events are notifications that occur when users interact with your application, such as clicking buttons, typing text, or moving the mouse. Event handling makes applications interactive and responsive.


// Simple Button Click Event
Button button = new Button("Click Me!");
button.setOnAction(event -> {
    System.out.println("Button was clicked!");
});
                                    

Output:

Common Event Types

👆

Mouse Events

Click, hover, drag interactions

node.setOnMouseClicked(e -> 
    handleClick());
⌨️

Keyboard Events

Key press and release events

scene.setOnKeyPressed(e -> 
    handleKeyPress(e));
🎯

Action Events

Button clicks, menu selections

button.setOnAction(e -> 
    performAction());
🔄

Change Events

Property value changes

slider.valueProperty().addListener(
    (obs, old, val) -> update());

🔹 Button and Action Events

The most common events in JavaFX applications:

// Different ways to handle button events
Button button1 = new Button("Lambda Style");
button1.setOnAction(event -> {
    System.out.println("Lambda event handler");
    // Your code here
});

Button button2 = new Button("Method Reference");
button2.setOnAction(this::handleButtonClick);

Button button3 = new Button("Anonymous Class");
button3.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent event) {
        System.out.println("Anonymous class handler");
    }
});

// Method for method reference
private void handleButtonClick(ActionEvent event) {
    Button source = (Button) event.getSource();
    System.out.println("Button clicked: " + source.getText());
}

Output:

🔹 Mouse Events

Handling various mouse interactions:

Rectangle rectangle = new Rectangle(100, 100, Color.LIGHTBLUE);

// Mouse click events
rectangle.setOnMouseClicked(event -> {
    if (event.getButton() == MouseButton.PRIMARY) {
        System.out.println("Left click at: " + event.getX() + ", " + event.getY());
    } else if (event.getButton() == MouseButton.SECONDARY) {
        System.out.println("Right click detected");
    }
});

// Mouse enter and exit (hover effects)
rectangle.setOnMouseEntered(event -> {
    rectangle.setFill(Color.LIGHTGREEN);
    rectangle.setCursor(Cursor.HAND);
});

rectangle.setOnMouseExited(event -> {
    rectangle.setFill(Color.LIGHTBLUE);
    rectangle.setCursor(Cursor.DEFAULT);
});

// Mouse drag events
rectangle.setOnMouseDragged(event -> {
    rectangle.setX(event.getX() - 50);
    rectangle.setY(event.getY() - 50);
    System.out.println("Dragging to: " + event.getX() + ", " + event.getY());
});

Output:

🔹 Keyboard Events

Capturing and responding to keyboard input:

TextField textField = new TextField();
Label statusLabel = new Label("Type something...");

// Key pressed events
textField.setOnKeyPressed(event -> {
    KeyCode key = event.getCode();
    
    switch (key) {
        case ENTER:
            statusLabel.setText("Enter key pressed!");
            break;
        case ESCAPE:
            textField.clear();
            statusLabel.setText("Text cleared");
            break;
        case F1:
            statusLabel.setText("Help key pressed");
            break;
        default:
            statusLabel.setText("Key pressed: " + key.getName());
    }
});

// Text change events
textField.textProperty().addListener((observable, oldValue, newValue) -> {
    statusLabel.setText("Text changed to: " + newValue);
});

// Scene-level keyboard events
scene.setOnKeyPressed(event -> {
    if (event.isControlDown() && event.getCode() == KeyCode.S) {
        System.out.println("Ctrl+S pressed - Save action");
        event.consume(); // Prevent default behavior
    }
});

Output:

Type something...

🔹 Property Change Events

Listening to property changes in JavaFX components:

Slider slider = new Slider(0, 100, 50);
Label valueLabel = new Label("Value: 50");
ProgressBar progressBar = new ProgressBar(0.5);

// Listen to slider value changes
slider.valueProperty().addListener((observable, oldValue, newValue) -> {
    int intValue = newValue.intValue();
    valueLabel.setText("Value: " + intValue);
    progressBar.setProgress(intValue / 100.0);
});

CheckBox checkBox = new CheckBox("Enable notifications");
Label checkStatus = new Label("Notifications: OFF");

// Listen to checkbox state changes
checkBox.selectedProperty().addListener((observable, oldValue, newValue) -> {
    checkStatus.setText("Notifications: " + (newValue ? "ON" : "OFF"));
});

ComboBox<String> comboBox = new ComboBox<>();
comboBox.getItems().addAll("Option 1", "Option 2", "Option 3");
Label comboStatus = new Label("No selection");

// Listen to combo box selection changes
comboBox.getSelectionModel().selectedItemProperty().addListener(
    (observable, oldValue, newValue) -> {
        comboStatus.setText("Selected: " + newValue);
    }
);

Output:

Value: 50
Notifications: OFF

🔹 Event Handling Best Practices

Tips for effective event handling in JavaFX:

Best Practices:

  • Use Lambda Expressions: More concise and readable for simple handlers
  • Separate Logic: Keep event handlers simple, delegate complex logic to methods
  • Event Consumption: Use event.consume() to prevent event bubbling when needed
  • Weak References: Use weak listeners for long-lived objects to prevent memory leaks
  • Thread Safety: Update UI components only from the JavaFX Application Thread
// Good practice example
public class EventHandlingExample extends VBox {
    private TextField inputField;
    private Label outputLabel;
    
    public EventHandlingExample() {
        setupUI();
        setupEventHandlers();
    }
    
    private void setupUI() {
        inputField = new TextField();
        outputLabel = new Label("Enter text above");
        Button processButton = new Button("Process");
        
        getChildren().addAll(inputField, processButton, outputLabel);
        setSpacing(10);
    }
    
    private void setupEventHandlers() {
        // Simple lambda for button
        Button processButton = (Button) getChildren().get(1);
        processButton.setOnAction(e -> processInput());
        
        // Method reference for text changes
        inputField.textProperty().addListener(this::onTextChanged);
    }
    
    private void processInput() {
        String text = inputField.getText();
        if (!text.isEmpty()) {
            outputLabel.setText("Processed: " + text.toUpperCase());
        }
    }
    
    private void onTextChanged(ObservableValue<? extends String> obs, 
                              String oldText, String newText) {
        if (newText.length() > 50) {
            inputField.setText(oldText); // Limit input length
        }
    }
}

🧠 Test Your Knowledge

Which method is used to handle button click events?