Java Programming GUI Framework
Modern UI

JavaFX - Modern GUI Development

Master JavaFX: Learn to create modern, rich desktop applications with Scene Builder, FXML, CSS styling, animations, charts, and 3D graphics using Java's premier GUI framework.

Rich UI Controls

50+ Built-in controls

FXML & CSS

Separation of concerns

Charts & 3D

Advanced visualization

Hardware Accelerated

GPU rendering

1. Introduction to JavaFX

JavaFX is a modern, rich-client platform for building cross-platform desktop applications. It replaces Swing as the standard GUI library for Java SE and provides hardware-accelerated graphics, CSS styling, FXML for declarative UI design, and a comprehensive set of UI controls.

Key Features
  • Hardware Acceleration: GPU-accelerated rendering
  • FXML: XML-based UI declaration
  • CSS Styling: Full CSS3 support for styling
  • Scene Builder: Visual layout tool
  • Rich Controls: 50+ built-in UI controls
  • WebView: Embedded web browser
  • 3D Graphics: Built-in 3D support
JavaFX vs Swing
  • Performance: JavaFX uses hardware acceleration
  • Styling: CSS vs Look and Feel
  • Architecture: Scene Graph vs AWT/Swing
  • Modern Features: Built-in animations, 3D, media
  • Tooling: Scene Builder vs NetBeans Matisse
  • Future: Actively developed vs maintenance

JavaFX Architecture

Scene Graph → Prism (Rendering) → Glass (Window Toolkit) → Quantum (Threading)
JavaFX uses a retained mode rendering model with a scene graph data structure for efficient UI updates and hardware-accelerated graphics.

FirstJavaFXApp.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class FirstJavaFXApp extends Application {
    
    @Override
    public void start(Stage primaryStage) {
        // Create UI controls
        Label titleLabel = new Label("Welcome to JavaFX!");
        titleLabel.setStyle("-fx-font-size: 24px; -fx-font-weight: bold; -fx-text-fill: #3D8B37;");
        
        Label messageLabel = new Label("This is your first JavaFX application.");
        messageLabel.setStyle("-fx-font-size: 14px; -fx-text-fill: #666;");
        
        Button clickButton = new Button("Click Me!");
        clickButton.setStyle("-fx-background-color: #3D8B37; -fx-text-fill: white; -fx-font-size: 16px; " +
                            "-fx-padding: 10px 20px; -fx-border-radius: 5px;");
        
        Button exitButton = new Button("Exit");
        exitButton.setStyle("-fx-background-color: #FF6B35; -fx-text-fill: white; -fx-font-size: 16px; " +
                           "-fx-padding: 10px 20px; -fx-border-radius: 5px;");
        
        // Add event handlers
        clickButton.setOnAction(event -> {
            messageLabel.setText("Button clicked! Current time: " + java.time.LocalTime.now());
            clickButton.setStyle("-fx-background-color: #00A8E8; -fx-text-fill: white; -fx-font-size: 16px; " +
                               "-fx-padding: 10px 20px; -fx-border-radius: 5px;");
        });
        
        exitButton.setOnAction(event -> {
            System.out.println("Application exiting...");
            primaryStage.close();
        });
        
        // Create layout
        VBox root = new VBox(20); // 20 pixels spacing between children
        root.setStyle("-fx-padding: 40px; -fx-background-color: #f8f9fa; -fx-alignment: center;");
        root.getChildren().addAll(titleLabel, messageLabel, clickButton, exitButton);
        
        // Create scene
        Scene scene = new Scene(root, 400, 300);
        
        // Configure stage (window)
        primaryStage.setTitle("First JavaFX Application");
        primaryStage.setScene(scene);
        primaryStage.show();
        
        // Window close request handler
        primaryStage.setOnCloseRequest(event -> {
            System.out.println("Window is closing...");
            // You could add confirmation dialog here
        });
    }
    
    public static void main(String[] args) {
        // Launch the JavaFX application
        launch(args);
    }
}

Welcome to JavaFX!

This is your first JavaFX application.

2. Scene Builder & FXML

FXML is an XML-based markup language for defining JavaFX user interfaces. Scene Builder is a visual layout tool that generates FXML, allowing designers to create interfaces without writing code.

LoginForm.fxml
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<VBox xmlns="http://javafx.com/javafx" 
      xmlns:fx="http://javafx.com/fxml" 
      fx:controller="com.example.LoginController"
      spacing="20" 
      alignment="CENTER"
      style="-fx-background-color: linear-gradient(to bottom right, #f8f9fa, #e9ecef);"
      prefWidth="400" prefHeight="500">
    
    <padding>
        <Insets top="40" right="40" bottom="40" left="40"/>
    </padding>
    
    <!-- Header -->
    <VBox spacing="10" alignment="CENTER">
        <Label text="Welcome Back" 
               style="-fx-font-size: 32px; -fx-font-weight: bold; -fx-text-fill: #3D8B37;"/>
        <Label text="Sign in to your account" 
               style="-fx-font-size: 14px; -fx-text-fill: #666;"/>
    </VBox>
    
    <!-- Login Form -->
    <VBox spacing="15" prefWidth="300">
        <!-- Username Field -->
        <VBox spacing="5">
            <Label text="Username" style="-fx-font-weight: bold;"/>
            <TextField fx:id="usernameField" 
                      promptText="Enter your username"
                      style="-fx-padding: 10px; -fx-font-size: 14px;"/>
        </VBox>
        
        <!-- Password Field -->
        <VBox spacing="5">
            <Label text="Password" style="-fx-font-weight: bold;"/>
            <PasswordField fx:id="passwordField" 
                          promptText="Enter your password"
                          style="-fx-padding: 10px; -fx-font-size: 14px;"/>
        </VBox>
        
        <!-- Remember Me Checkbox -->
        <HBox spacing="10" alignment="CENTER_LEFT">
            <CheckBox fx:id="rememberCheckbox" text="Remember me"/>
            <Region HBox.hgrow="ALWAYS"/>
            <Hyperlink text="Forgot password?" onAction="#onForgotPassword"/>
        </HBox>
        
        <!-- Login Button -->
        <Button text="Sign In" 
                fx:id="loginButton"
                onAction="#onLogin"
                defaultButton="true"
                style="-fx-background-color: #3D8B37; -fx-text-fill: white; 
                       -fx-font-size: 16px; -fx-font-weight: bold;
                       -fx-padding: 12px 0; -fx-background-radius: 5px;"
                prefWidth="300"/>
        
        <!-- Error Message -->
        <Label fx:id="errorLabel" 
               style="-fx-text-fill: #dc3545; -fx-font-size: 12px;" 
               visible="false"/>
    </VBox>
    
    <!-- Divider -->
    <Separator prefWidth="300"/>
    
    <!-- Social Login -->
    <VBox spacing="10" alignment="CENTER">
        <Label text="Or sign in with" style="-fx-text-fill: #666;"/>
        <HBox spacing="15" alignment="CENTER">
            <Button text="Google" 
                    onAction="#onGoogleLogin"
                    style="-fx-background-color: white; -fx-text-fill: #666;
                           -fx-border-color: #ddd; -fx-border-width: 1px;
                           -fx-padding: 10px 20px;"/>
            <Button text="GitHub" 
                    onAction="#onGithubLogin"
                    style="-fx-background-color: #333; -fx-text-fill: white;
                           -fx-padding: 10px 20px;"/>
        </HBox>
    </VBox>
    
    <!-- Sign Up Link -->
    <HBox spacing="5" alignment="CENTER">
        <Label text="Don't have an account?" style="-fx-text-fill: #666;"/>
        <Hyperlink text="Sign up" onAction="#onSignUp"/>
    </HBox>
    
</VBox>
LoginController.java
package com.example;

import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.event.ActionEvent;
import javafx.scene.control.Alert.AlertType;

public class LoginController {
    
    @FXML
    private TextField usernameField;
    
    @FXML
    private PasswordField passwordField;
    
    @FXML
    private CheckBox rememberCheckbox;
    
    @FXML
    private Button loginButton;
    
    @FXML
    private Label errorLabel;
    
    // Initialize method - called after FXML is loaded
    @FXML
    private void initialize() {
        // Set up initial state
        loginButton.setDisable(true);
        
        // Add listeners for input validation
        usernameField.textProperty().addListener((observable, oldValue, newValue) -> {
            validateInput();
        });
        
        passwordField.textProperty().addListener((observable, oldValue, newValue) -> {
            validateInput();
        });
        
        // Enter key support
        usernameField.setOnAction(this::onLogin);
        passwordField.setOnAction(this::onLogin);
    }
    
    @FXML
    private void onLogin(ActionEvent event) {
        String username = usernameField.getText();
        String password = passwordField.getText();
        boolean rememberMe = rememberCheckbox.isSelected();
        
        // Clear previous errors
        errorLabel.setVisible(false);
        
        // Validate credentials (in real app, check against database)
        if (isValidCredentials(username, password)) {
            // Successful login
            showAlert(AlertType.INFORMATION, "Login Successful", 
                     "Welcome, " + username + "!");
            
            if (rememberMe) {
                saveCredentials(username, password);
            }
            
            // Navigate to main application
            navigateToMainApp();
        } else {
            // Failed login
            errorLabel.setText("Invalid username or password");
            errorLabel.setVisible(true);
            
            // Visual feedback
            usernameField.setStyle("-fx-border-color: #dc3545; -fx-border-width: 2px;");
            passwordField.setStyle("-fx-border-color: #dc3545; -fx-border-width: 2px;");
        }
    }
    
    @FXML
    private void onForgotPassword(ActionEvent event) {
        showAlert(AlertType.INFORMATION, "Password Reset", 
                 "A password reset link has been sent to your email.");
    }
    
    @FXML
    private void onGoogleLogin(ActionEvent event) {
        showAlert(AlertType.INFORMATION, "Google Login", 
                 "Redirecting to Google authentication...");
    }
    
    @FXML
    private void onGithubLogin(ActionEvent event) {
        showAlert(AlertType.INFORMATION, "GitHub Login", 
                 "Redirecting to GitHub authentication...");
    }
    
    @FXML
    private void onSignUp(ActionEvent event) {
        showAlert(AlertType.INFORMATION, "Sign Up", 
                 "Redirecting to registration page...");
    }
    
    private void validateInput() {
        String username = usernameField.getText();
        String password = passwordField.getText();
        
        boolean isValid = !username.trim().isEmpty() && 
                         !password.trim().isEmpty() &&
                         username.length() >= 3 &&
                         password.length() >= 6;
        
        loginButton.setDisable(!isValid);
        
        // Clear error styles when typing
        if (!username.trim().isEmpty()) {
            usernameField.setStyle("");
        }
        if (!password.trim().isEmpty()) {
            passwordField.setStyle("");
        }
    }
    
    private boolean isValidCredentials(String username, String password) {
        // Demo validation - replace with real authentication
        return "admin".equals(username) && "password123".equals(password);
    }
    
    private void saveCredentials(String username, String password) {
        // Save to preferences or secure storage
        System.out.println("Credentials saved for: " + username);
    }
    
    private void navigateToMainApp() {
        // Code to switch to main application scene
        System.out.println("Navigating to main application...");
    }
    
    private void showAlert(AlertType type, String title, String message) {
        Alert alert = new Alert(type);
        alert.setTitle(title);
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }
}
MainApp.java
package com.example;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class MainApp extends Application {
    
    @Override
    public void start(Stage primaryStage) throws Exception {
        // Load FXML file
        FXMLLoader loader = new FXMLLoader(getClass().getResource("LoginForm.fxml"));
        Parent root = loader.load();
        
        // Get controller (optional - for advanced scenarios)
        LoginController controller = loader.getController();
        
        // Create scene
        Scene scene = new Scene(root);
        
        // Apply CSS stylesheet (optional)
        scene.getStylesheets().add(getClass().getResource("styles.css").toExternalForm());
        
        // Configure stage
        primaryStage.setTitle("JavaFX Login Application");
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        
        // Show the stage
        primaryStage.show();
        
        // Center window on screen
        primaryStage.centerOnScreen();
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}
FXML Benefits
  • Separation of Concerns: UI layout vs business logic
  • Tool Support: Scene Builder visual design
  • Maintainability: Easier to modify UI structure
  • Internationalization: Easy to localize text
  • Reusability: Can include other FXML files
  • Performance: Loaded once, cached for reuse
Scene Builder Tips
  • Use fx:id for controller access
  • Set prefWidth/Height for responsive layouts
  • Use Controller Factory for dependency injection
  • Organize with AnchorPane or GridPane
  • Preview with different CSS stylesheets
  • Export for different screen resolutions

3. JavaFX UI Controls

JavaFX provides a comprehensive set of built-in UI controls for creating modern desktop applications. All controls support CSS styling, event handling, and data binding.

ControlsDemo.java
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import java.time.LocalDate;

public class ControlsDemo extends Application {
    
    @Override
    public void start(Stage primaryStage) {
        // Create main layout with tabs
        TabPane tabPane = new TabPane();
        
        // Tab 1: Basic Controls
        Tab basicTab = new Tab("Basic Controls", createBasicControlsPane());
        basicTab.setClosable(false);
        
        // Tab 2: Selection Controls
        Tab selectionTab = new Tab("Selection Controls", createSelectionControlsPane());
        selectionTab.setClosable(false);
        
        // Tab 3: Data Entry
        Tab dataTab = new Tab("Data Entry", createDataEntryPane());
        dataTab.setClosable(false);
        
        // Tab 4: Advanced Controls
        Tab advancedTab = new Tab("Advanced", createAdvancedControlsPane());
        advancedTab.setClosable(false);
        
        tabPane.getTabs().addAll(basicTab, selectionTab, dataTab, advancedTab);
        
        // Create scene
        Scene scene = new Scene(tabPane, 800, 600);
        
        // Apply CSS
        scene.getStylesheets().add(getClass().getResource("controls.css").toExternalForm());
        
        // Configure stage
        primaryStage.setTitle("JavaFX Controls Demo");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private VBox createBasicControlsPane() {
        VBox vbox = new VBox(15);
        vbox.setPadding(new Insets(20));
        vbox.setStyle("-fx-background-color: #f8f9fa;");
        
        // Labels
        Label title = new Label("Basic Controls Demo");
        title.setStyle("-fx-font-size: 24px; -fx-font-weight: bold; -fx-text-fill: #3D8B37;");
        
        // Buttons
        HBox buttonBox = new HBox(10);
        Button primaryBtn = new Button("Primary");
        primaryBtn.getStyleClass().add("primary-button");
        
        Button secondaryBtn = new Button("Secondary");
        secondaryBtn.getStyleClass().add("secondary-button");
        
        Button successBtn = new Button("Success");
        successBtn.getStyleClass().add("success-button");
        
        Button dangerBtn = new Button("Danger");
        dangerBtn.getStyleClass().add("danger-button");
        
        // Toggle buttons
        ToggleButton toggleBtn = new ToggleButton("Toggle Me");
        toggleBtn.selectedProperty().addListener((obs, oldVal, newVal) -> {
            System.out.println("Toggle button: " + newVal);
        });
        
        buttonBox.getChildren().addAll(primaryBtn, secondaryBtn, successBtn, dangerBtn, toggleBtn);
        
        // Text Input
        VBox inputBox = new VBox(10);
        Label inputLabel = new Label("Text Input:");
        TextField textField = new TextField();
        textField.setPromptText("Enter text here...");
        textField.setPrefWidth(300);
        
        PasswordField passwordField = new PasswordField();
        passwordField.setPromptText("Enter password...");
        passwordField.setPrefWidth(300);
        
        TextArea textArea = new TextArea();
        textArea.setPromptText("Multi-line text here...");
        textArea.setPrefRowCount(4);
        textArea.setPrefWidth(300);
        
        inputBox.getChildren().addAll(inputLabel, textField, passwordField, textArea);
        
        // Progress indicators
        VBox progressBox = new VBox(10);
        Label progressLabel = new Label("Progress Indicators:");
        ProgressBar progressBar = new ProgressBar(0.5);
        ProgressIndicator progressIndicator = new ProgressIndicator(0.7);
        Slider slider = new Slider(0, 100, 50);
        
        progressBox.getChildren().addAll(progressLabel, progressBar, progressIndicator, slider);
        
        vbox.getChildren().addAll(title, buttonBox, inputBox, progressBox);
        return vbox;
    }
    
    private VBox createSelectionControlsPane() {
        VBox vbox = new VBox(15);
        vbox.setPadding(new Insets(20));
        
        // Checkboxes
        VBox checkboxBox = new VBox(10);
        Label checkboxLabel = new Label("Checkboxes:");
        CheckBox option1 = new CheckBox("Option 1");
        CheckBox option2 = new CheckBox("Option 2");
        CheckBox option3 = new CheckBox("Option 3");
        
        // Three-state checkbox
        CheckBox indeterminateCheck = new CheckBox("Allow Indeterminate");
        indeterminateCheck.setAllowIndeterminate(true);
        indeterminateCheck.setIndeterminate(true);
        
        checkboxBox.getChildren().addAll(checkboxLabel, option1, option2, option3, indeterminateCheck);
        
        // Radio buttons
        VBox radioBox = new VBox(10);
        Label radioLabel = new Label("Radio Buttons:");
        ToggleGroup group = new ToggleGroup();
        RadioButton radio1 = new RadioButton("Choice A");
        radio1.setToggleGroup(group);
        RadioButton radio2 = new RadioButton("Choice B");
        radio2.setToggleGroup(group);
        RadioButton radio3 = new RadioButton("Choice C");
        radio3.setToggleGroup(group);
        
        // Select first radio button
        radio1.setSelected(true);
        
        radioBox.getChildren().addAll(radioLabel, radio1, radio2, radio3);
        
        // ComboBox
        VBox comboBox = new VBox(10);
        Label comboLabel = new Label("ComboBox:");
        ObservableList options = FXCollections.observableArrayList(
            "Java", "Python", "JavaScript", "C++", "C#", "Go", "Rust"
        );
        ComboBox languageCombo = new ComboBox<>(options);
        languageCombo.setPromptText("Select a language");
        languageCombo.setPrefWidth(200);
        
        // Display selected value
        Label selectedLabel = new Label("Selected: None");
        languageCombo.valueProperty().addListener((obs, oldVal, newVal) -> {
            selectedLabel.setText("Selected: " + newVal);
        });
        
        comboBox.getChildren().addAll(comboLabel, languageCombo, selectedLabel);
        
        // ListView
        VBox listBox = new VBox(10);
        Label listLabel = new Label("ListView:");
        ObservableList items = FXCollections.observableArrayList(
            "Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6"
        );
        ListView listView = new ListView<>(items);
        listView.setPrefHeight(150);
        listView.setPrefWidth(200);
        
        // Multiple selection
        listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        
        listBox.getChildren().addAll(listLabel, listView);
        
        vbox.getChildren().addAll(checkboxBox, radioBox, comboBox, listBox);
        return vbox;
    }
    
    private VBox createDataEntryPane() {
        VBox vbox = new VBox(15);
        vbox.setPadding(new Insets(20));
        
        // Date Picker
        VBox dateBox = new VBox(10);
        Label dateLabel = new Label("Date Picker:");
        DatePicker datePicker = new DatePicker(LocalDate.now());
        datePicker.setPrefWidth(200);
        
        datePicker.valueProperty().addListener((obs, oldDate, newDate) -> {
            System.out.println("Selected date: " + newDate);
        });
        
        dateBox.getChildren().addAll(dateLabel, datePicker);
        
        // Color Picker
        VBox colorBox = new VBox(10);
        Label colorLabel = new Label("Color Picker:");
        ColorPicker colorPicker = new ColorPicker(Color.BLUE);
        colorPicker.setPrefWidth(200);
        
        // Preview circle
        Circle colorPreview = new Circle(20);
        colorPreview.setFill(Color.BLUE);
        
        colorPicker.valueProperty().addListener((obs, oldColor, newColor) -> {
            colorPreview.setFill(newColor);
        });
        
        HBox colorPreviewBox = new HBox(10, colorPicker, colorPreview);
        colorPreviewBox.setAlignment(Pos.CENTER_LEFT);
        
        colorBox.getChildren().addAll(colorLabel, colorPreviewBox);
        
        // Spinner
        VBox spinnerBox = new VBox(10);
        Label spinnerLabel = new Label("Spinners:");
        
        Spinner intSpinner = new Spinner<>(1, 100, 50);
        intSpinner.setPrefWidth(150);
        
        Spinner doubleSpinner = new Spinner<>(0.0, 10.0, 5.0, 0.5);
        doubleSpinner.setPrefWidth(150);
        
        HBox spinnerHBox = new HBox(20, intSpinner, doubleSpinner);
        
        spinnerBox.getChildren().addAll(spinnerLabel, spinnerHBox);
        
        // TableView
        VBox tableBox = new VBox(10);
        Label tableLabel = new Label("TableView:");
        
        TableView tableView = new TableView<>();
        tableView.setPrefHeight(200);
        
        // Define columns
        TableColumn nameColumn = new TableColumn<>("Name");
        nameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
        
        TableColumn ageColumn = new TableColumn<>("Age");
        ageColumn.setCellValueFactory(cellData -> cellData.getValue().ageProperty().asObject());
        
        TableColumn emailColumn = new TableColumn<>("Email");
        emailColumn.setCellValueFactory(cellData -> cellData.getValue().emailProperty());
        
        tableView.getColumns().addAll(nameColumn, ageColumn, emailColumn);
        
        // Add sample data
        ObservableList people = FXCollections.observableArrayList(
            new Person("Alice Johnson", 28, "alice@example.com"),
            new Person("Bob Smith", 35, "bob@example.com"),
            new Person("Charlie Brown", 42, "charlie@example.com"),
            new Person("Diana Prince", 30, "diana@example.com")
        );
        tableView.setItems(people);
        
        tableBox.getChildren().addAll(tableLabel, tableView);
        
        vbox.getChildren().addAll(dateBox, colorBox, spinnerBox, tableBox);
        return vbox;
    }
    
    private VBox createAdvancedControlsPane() {
        VBox vbox = new VBox(15);
        vbox.setPadding(new Insets(20));
        
        // TreeView
        VBox treeBox = new VBox(10);
        Label treeLabel = new Label("TreeView:");
        
        TreeItem rootItem = new TreeItem<>("Projects");
        rootItem.setExpanded(true);
        
        TreeItem javaProjects = new TreeItem<>("Java Projects");
        javaProjects.getChildren().addAll(
            new TreeItem<>("Inventory System"),
            new TreeItem<>("E-commerce Platform"),
            new TreeItem<>("Banking Application")
        );
        
        TreeItem webProjects = new TreeItem<>("Web Projects");
        webProjects.getChildren().addAll(
            new TreeItem<>("React Dashboard"),
            new TreeItem<>("Angular E-commerce"),
            new TreeItem<>("Vue.js Admin Panel")
        );
        
        rootItem.getChildren().addAll(javaProjects, webProjects);
        
        TreeView treeView = new TreeView<>(rootItem);
        treeView.setPrefHeight(200);
        
        treeBox.getChildren().addAll(treeLabel, treeView);
        
        // Accordion with TitledPane
        VBox accordionBox = new VBox(10);
        Label accordionLabel = new Label("Accordion:");
        
        TitledPane pane1 = new TitledPane("General Settings", 
            new VBox(10, new CheckBox("Auto-update"), new CheckBox("Notifications")));
        
        TitledPane pane2 = new TitledPane("Privacy", 
            new VBox(10, new CheckBox("Collect usage data"), new CheckBox("Share analytics")));
        
        TitledPane pane3 = new TitledPane("Advanced", 
            new VBox(10, new TextField("API Key"), new Button("Validate")));
        
        Accordion accordion = new Accordion(pane1, pane2, pane3);
        accordion.setPrefHeight(200);
        
        accordionBox.getChildren().addAll(accordionLabel, accordion);
        
        // WebView
        VBox webBox = new VBox(10);
        Label webLabel = new Label("WebView (Embedded Browser):");
        
        // Note: WebView requires JavaFX WebKit module
        // WebView webView = new WebView();
        // webView.getEngine().load("https://openjfx.io");
        // webView.setPrefHeight(200);
        
        Label webViewNote = new Label("Note: WebView requires JavaFX WebKit module");
        webViewNote.setStyle("-fx-font-style: italic; -fx-text-fill: #666;");
        
        webBox.getChildren().addAll(webLabel, webViewNote);
        
        vbox.getChildren().addAll(treeBox, accordionBox, webBox);
        return vbox;
    }
    
    // Model class for TableView
    public static class Person {
        private final StringProperty name = new SimpleStringProperty();
        private final IntegerProperty age = new SimpleIntegerProperty();
        private final StringProperty email = new SimpleStringProperty();
        
        public Person(String name, int age, String email) {
            this.name.set(name);
            this.age.set(age);
            this.email.set(email);
        }
        
        public StringProperty nameProperty() { return name; }
        public IntegerProperty ageProperty() { return age; }
        public StringProperty emailProperty() { return email; }
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}
Control Category Key Controls Description Common Use
Basic Label, Button, TextField, TextArea Fundamental UI elements Forms, navigation, input
Selection CheckBox, RadioButton, ComboBox, ListView Single/multiple selection Options, preferences, lists
Data Entry DatePicker, ColorPicker, Spinner, TableView Specialized data input Forms, data management
Containers TabPane, Accordion, TitledPane, SplitPane Organize and group controls Complex layouts, navigation
Advanced TreeView, WebView, HTMLEditor, ProgressBar Specialized functionality Browsers, editors, progress

4. JavaFX CSS Styling

JavaFX supports CSS (Cascading Style Sheets) for styling UI components. Unlike web CSS, JavaFX CSS has its own properties and selectors optimized for desktop applications.

styles.css
/* JavaFX CSS - Modern Application Styles */

/* === Root Styles & Variables === */
.root {
    -fx-primary-color: #3D8B37;
    -fx-secondary-color: #FF6B35;
    -fx-accent-color: #00A8E8;
    -fx-light-color: #F8F9FA;
    -fx-dark-color: #343A40;
    -fx-success-color: #28A745;
    -fx-danger-color: #DC3545;
    -fx-warning-color: #FFC107;
    -fx-info-color: #17A2B8;
    
    /* Font variables */
    -fx-font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
    -fx-font-size: 14px;
    
    /* Background gradient */
    -fx-background-color: linear-gradient(to bottom right, #f8f9fa, #e9ecef);
}

/* === Typography === */
.label {
    -fx-text-fill: -fx-dark-color;
}

.label.heading {
    -fx-font-size: 24px;
    -fx-font-weight: bold;
    -fx-text-fill: -fx-primary-color;
}

.label.subheading {
    -fx-font-size: 18px;
    -fx-font-weight: 600;
    -fx-text-fill: #666;
}

.label.caption {
    -fx-font-size: 12px;
    -fx-text-fill: #888;
    -fx-font-style: italic;
}

/* === Button Styles === */
.button {
    -fx-font-weight: 600;
    -fx-font-size: 14px;
    -fx-padding: 10px 20px;
    -fx-background-radius: 5px;
    -fx-border-radius: 5px;
    -fx-cursor: hand;
    -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 4, 0, 0, 2);
    -fx-transition: all 0.3s;
}

.button:hover {
    -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.2), 6, 0, 0, 3);
    -fx-translate-y: -1px;
}

.button:pressed {
    -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 2, 0, 0, 1);
    -fx-translate-y: 0px;
}

.primary-button {
    -fx-background-color: -fx-primary-color;
    -fx-text-fill: white;
}

.primary-button:hover {
    -fx-background-color: derive(-fx-primary-color, -10%);
}

.secondary-button {
    -fx-background-color: -fx-secondary-color;
    -fx-text-fill: white;
}

.secondary-button:hover {
    -fx-background-color: derive(-fx-secondary-color, -10%);
}

.success-button {
    -fx-background-color: -fx-success-color;
    -fx-text-fill: white;
}

.danger-button {
    -fx-background-color: -fx-danger-color;
    -fx-text-fill: white;
}

.outline-button {
    -fx-background-color: transparent;
    -fx-border-color: -fx-primary-color;
    -fx-border-width: 2px;
    -fx-text-fill: -fx-primary-color;
}

.outline-button:hover {
    -fx-background-color: -fx-primary-color;
    -fx-text-fill: white;
}

/* === Text Input Styles === */
.text-field, .password-field, .text-area {
    -fx-background-color: white;
    -fx-border-color: #ddd;
    -fx-border-width: 1px;
    -fx-border-radius: 4px;
    -fx-padding: 10px;
    -fx-font-size: 14px;
}

.text-field:focused, .password-field:focused, .text-area:focused {
    -fx-border-color: -fx-primary-color;
    -fx-border-width: 2px;
    -fx-effect: dropshadow(gaussian, rgba(61, 139, 55, 0.2), 10, 0, 0, 0);
}

.text-field.error, .password-field.error {
    -fx-border-color: -fx-danger-color;
    -fx-border-width: 2px;
}

.text-area .content {
    -fx-background-color: white;
    -fx-background-radius: 4px;
}

/* === ComboBox Styles === */
.combo-box {
    -fx-background-color: white;
    -fx-border-color: #ddd;
    -fx-border-width: 1px;
    -fx-border-radius: 4px;
    -fx-padding: 5px;
}

.combo-box .arrow-button {
    -fx-background-color: transparent;
}

.combo-box .list-cell {
    -fx-padding: 8px;
}

.combo-box-popup .list-view {
    -fx-background-color: white;
    -fx-border-color: #ddd;
    -fx-border-width: 1px;
}

.combo-box-popup .list-cell {
    -fx-padding: 8px 12px;
}

.combo-box-popup .list-cell:hover {
    -fx-background-color: -fx-light-color;
}

.combo-box-popup .list-cell:selected {
    -fx-background-color: -fx-primary-color;
    -fx-text-fill: white;
}

/* === CheckBox & RadioButton === */
.check-box, .radio-button {
    -fx-text-fill: -fx-dark-color;
    -fx-font-size: 14px;
}

.check-box .box, .radio-button .radio {
    -fx-background-color: white;
    -fx-border-color: #ccc;
    -fx-border-width: 2px;
    -fx-border-radius: 3px;
}

.check-box:selected .mark, .radio-button:selected .dot {
    -fx-background-color: -fx-primary-color;
}

.check-box:hover .box, .radio-button:hover .radio {
    -fx-border-color: -fx-primary-color;
}

/* === Slider & Progress === */
.slider .track {
    -fx-background-color: #e9ecef;
    -fx-background-radius: 2px;
}

.slider .thumb {
    -fx-background-color: -fx-primary-color;
    -fx-background-radius: 50%;
    -fx-pref-width: 20px;
    -fx-pref-height: 20px;
}

.progress-bar .track {
    -fx-background-color: #e9ecef;
    -fx-background-radius: 3px;
}

.progress-bar .bar {
    -fx-background-color: -fx-primary-color;
    -fx-background-radius: 3px;
    -fx-padding: 4px;
}

.progress-indicator .percentage {
    -fx-fill: -fx-dark-color;
}

/* === TableView Styles === */
.table-view {
    -fx-background-color: white;
    -fx-border-color: #ddd;
    -fx-border-width: 1px;
    -fx-border-radius: 4px;
}

.table-view .column-header {
    -fx-background-color: -fx-light-color;
    -fx-border-color: #ddd;
    -fx-border-width: 0 0 1px 0;
    -fx-font-weight: bold;
    -fx-text-fill: -fx-dark-color;
}

.table-view .table-row-cell {
    -fx-border-color: #f0f0f0;
    -fx-border-width: 0 0 1px 0;
}

.table-view .table-row-cell:even {
    -fx-background-color: #fafafa;
}

.table-view .table-row-cell:odd {
    -fx-background-color: white;
}

.table-view .table-row-cell:hover {
    -fx-background-color: #f0f8ff;
}

.table-view .table-row-cell:selected {
    -fx-background-color: -fx-primary-color;
    -fx-text-fill: white;
}

/* === TabPane Styles === */
.tab-pane {
    -fx-background-color: white;
}

.tab-pane .tab-header-area {
    -fx-background-color: -fx-light-color;
}

.tab-pane .tab {
    -fx-background-color: transparent;
    -fx-border-color: transparent;
    -fx-padding: 10px 20px;
    -fx-font-weight: 600;
}

.tab-pane .tab:selected {
    -fx-background-color: white;
    -fx-border-color: transparent transparent -fx-primary-color transparent;
    -fx-border-width: 0 0 3px 0;
}

.tab-pane .tab:hover {
    -fx-background-color: rgba(255, 255, 255, 0.5);
}

/* === ScrollBar Styles === */
.scroll-bar {
    -fx-background-color: transparent;
}

.scroll-bar .thumb {
    -fx-background-color: #ccc;
    -fx-background-radius: 4px;
}

.scroll-bar .thumb:hover {
    -fx-background-color: #999;
}

.scroll-bar .increment-button, .scroll-bar .decrement-button {
    -fx-background-color: transparent;
    -fx-padding: 0;
}

/* === Custom Components === */
.card {
    -fx-background-color: white;
    -fx-background-radius: 8px;
    -fx-border-color: #e9ecef;
    -fx-border-width: 1px;
    -fx-border-radius: 8px;
    -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.08), 10, 0, 0, 2);
    -fx-padding: 20px;
}

.card:hover {
    -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.12), 12, 0, 0, 3);
}

.alert-box {
    -fx-background-color: #fff3cd;
    -fx-border-color: #ffeaa7;
    -fx-border-width: 1px;
    -fx-border-radius: 4px;
    -fx-padding: 15px;
}

.alert-box.success {
    -fx-background-color: #d4edda;
    -fx-border-color: #c3e6cb;
}

.alert-box.error {
    -fx-background-color: #f8d7da;
    -fx-border-color: #f5c6cb;
}

/* === Animations === */
@keyframes fadeIn {
    from { -fx-opacity: 0; }
    to { -fx-opacity: 1; }
}

@keyframes slideIn {
    from { -fx-translate-x: -20px; -fx-opacity: 0; }
    to { -fx-translate-x: 0; -fx-opacity: 1; }
}

.fade-in {
    -fx-animation: fadeIn 0.5s;
}

.slide-in {
    -fx-animation: slideIn 0.3s;
}
CSSExample.java
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class CSSExample extends Application {
    
    @Override
    public void start(Stage primaryStage) {
        // Main container
        VBox root = new VBox(20);
        root.setPadding(new Insets(30));
        root.setAlignment(Pos.TOP_CENTER);
        
        // Title
        Label title = new Label("JavaFX CSS Styling Demo");
        title.getStyleClass().add("heading");
        
        // Card 1: Form
        VBox formCard = createFormCard();
        formCard.getStyleClass().add("card");
        
        // Card 2: Dashboard
        VBox dashboardCard = createDashboardCard();
        dashboardCard.getStyleClass().add("card");
        
        // Card 3: Alerts
        VBox alertsCard = createAlertsCard();
        alertsCard.getStyleClass().add("card");
        
        root.getChildren().addAll(title, formCard, dashboardCard, alertsCard);
        
        // Create scene and apply CSS
        Scene scene = new Scene(root, 900, 700);
        scene.getStylesheets().add(getClass().getResource("styles.css").toExternalForm());
        
        // Configure stage
        primaryStage.setTitle("JavaFX CSS Styling Example");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private VBox createFormCard() {
        VBox card = new VBox(15);
        card.setPadding(new Insets(20));
        
        Label cardTitle = new Label("User Registration Form");
        cardTitle.getStyleClass().add("subheading");
        
        // Form grid
        GridPane formGrid = new GridPane();
        formGrid.setHgap(15);
        formGrid.setVgap(10);
        
        // Row 1: Name
        formGrid.add(new Label("Full Name:"), 0, 0);
        TextField nameField = new TextField();
        nameField.setPromptText("Enter your full name");
        formGrid.add(nameField, 1, 0);
        
        // Row 2: Email
        formGrid.add(new Label("Email:"), 0, 1);
        TextField emailField = new TextField();
        emailField.setPromptText("example@domain.com");
        formGrid.add(emailField, 1, 1);
        
        // Row 3: Password
        formGrid.add(new Label("Password:"), 0, 2);
        PasswordField passwordField = new PasswordField();
        passwordField.setPromptText("Minimum 8 characters");
        formGrid.add(passwordField, 1, 2);
        
        // Row 4: Country
        formGrid.add(new Label("Country:"), 0, 3);
        ComboBox countryCombo = new ComboBox<>();
        countryCombo.getItems().addAll("United States", "Canada", "United Kingdom", "Australia", "Germany", "Japan");
        countryCombo.setPromptText("Select your country");
        formGrid.add(countryCombo, 1, 3);
        
        // Row 5: Newsletter
        CheckBox newsletterCheck = new CheckBox("Subscribe to newsletter");
        formGrid.add(newletterCheck, 1, 4);
        
        // Buttons
        HBox buttonBox = new HBox(10);
        buttonBox.setAlignment(Pos.CENTER_RIGHT);
        
        Button cancelBtn = new Button("Cancel");
        cancelBtn.getStyleClass().add("outline-button");
        
        Button submitBtn = new Button("Register");
        submitBtn.getStyleClass().add("primary-button");
        
        buttonBox.getChildren().addAll(cancelBtn, submitBtn);
        
        card.getChildren().addAll(cardTitle, formGrid, buttonBox);
        return card;
    }
    
    private VBox createDashboardCard() {
        VBox card = new VBox(15);
        card.setPadding(new Insets(20));
        
        Label cardTitle = new Label("Dashboard Metrics");
        cardTitle.getStyleClass().add("subheading");
        
        // Metrics grid
        GridPane metricsGrid = new GridPane();
        metricsGrid.setHgap(20);
        metricsGrid.setVgap(15);
        metricsGrid.setAlignment(Pos.CENTER);
        
        // Metric 1: Users
        VBox usersMetric = createMetricBox("Total Users", "1,245", "+12%", "success-button");
        metricsGrid.add(usersMetric, 0, 0);
        
        // Metric 2: Revenue
        VBox revenueMetric = createMetricBox("Monthly Revenue", "$45,230", "+8%", "primary-button");
        metricsGrid.add(revenueMetric, 1, 0);
        
        // Metric 3: Conversion
        VBox conversionMetric = createMetricBox("Conversion Rate", "3.2%", "-2%", "danger-button");
        metricsGrid.add(conversionMetric, 2, 0);
        
        // Metric 4: Active
        VBox activeMetric = createMetricBox("Active Sessions", "324", "+5%", "secondary-button");
        metricsGrid.add(activeMetric, 3, 0);
        
        // Progress section
        VBox progressBox = new VBox(10);
        progressBox.setPadding(new Insets(20, 0, 0, 0));
        
        Label progressLabel = new Label("Storage Usage");
        progressLabel.getStyleClass().add("subheading");
        
        ProgressBar storageBar = new ProgressBar(0.65);
        storageBar.setPrefWidth(300);
        
        Label storageText = new Label("65% used (325GB of 500GB)");
        storageText.getStyleClass().add("caption");
        
        progressBox.getChildren().addAll(progressLabel, storageBar, storageText);
        
        card.getChildren().addAll(cardTitle, metricsGrid, progressBox);
        return card;
    }
    
    private VBox createMetricBox(String title, String value, String change, String styleClass) {
        VBox metricBox = new VBox(5);
        metricBox.setAlignment(Pos.CENTER);
        metricBox.setPadding(new Insets(15));
        metricBox.setStyle("-fx-background-color: #f8f9fa; -fx-border-radius: 8px;");
        
        Label titleLabel = new Label(title);
        titleLabel.getStyleClass().add("caption");
        
        Label valueLabel = new Label(value);
        valueLabel.setStyle("-fx-font-size: 24px; -fx-font-weight: bold;");
        
        Button changeBtn = new Button(change);
        changeBtn.getStyleClass().add(styleClass);
        changeBtn.setStyle("-fx-padding: 5px 10px; -fx-font-size: 12px;");
        
        metricBox.getChildren().addAll(titleLabel, valueLabel, changeBtn);
        return metricBox;
    }
    
    private VBox createAlertsCard() {
        VBox card = new VBox(15);
        card.setPadding(new Insets(20));
        
        Label cardTitle = new Label("System Alerts & Notifications");
        cardTitle.getStyleClass().add("subheading");
        
        // Success alert
        HBox successAlert = createAlert("success", "✓", "System update completed successfully", "Just now");
        
        // Error alert
        HBox errorAlert = createAlert("error", "⚠", "Database connection failed. Retrying...", "5 minutes ago");
        
        // Warning alert
        HBox warningAlert = createAlert("warning", "!", "Storage space running low", "1 hour ago");
        
        // Info alert
        HBox infoAlert = createAlert("info", "ℹ", "New feature available: Dark mode", "2 hours ago");
        
        card.getChildren().addAll(cardTitle, successAlert, errorAlert, warningAlert, infoAlert);
        return card;
    }
    
    private HBox createAlert(String type, String icon, String message, String time) {
        HBox alertBox = new HBox(10);
        alertBox.setPadding(new Insets(12));
        alertBox.setAlignment(Pos.CENTER_LEFT);
        alertBox.getStyleClass().add("alert-box");
        
        if ("success".equals(type)) {
            alertBox.getStyleClass().add("success");
        } else if ("error".equals(type)) {
            alertBox.getStyleClass().add("error");
        }
        
        Label iconLabel = new Label(icon);
        iconLabel.setStyle("-fx-font-size: 18px; -fx-font-weight: bold;");
        
        VBox messageBox = new VBox(2);
        Label messageLabel = new Label(message);
        Label timeLabel = new Label(time);
        timeLabel.getStyleClass().add("caption");
        
        messageBox.getChildren().addAll(messageLabel, timeLabel);
        
        Region spacer = new Region();
        HBox.setHgrow(spacer, Priority.ALWAYS);
        
        Button dismissBtn = new Button("Dismiss");
        dismissBtn.getStyleClass().add("outline-button");
        dismissBtn.setStyle("-fx-padding: 5px 15px; -fx-font-size: 12px;");
        
        alertBox.getChildren().addAll(iconLabel, messageBox, spacer, dismissBtn);
        return alertBox;
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}

5. Animations & Visual Effects

JavaFX provides a comprehensive animation API and built-in visual effects for creating engaging, modern user interfaces.

AnimationsDemo.java
import javafx.animation.*;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.effect.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Duration;

public class AnimationsDemo extends Application {
    
    private Timeline pulseTimeline;
    private ParallelTransition parallelTransition;
    private SequentialTransition sequentialTransition;
    
    @Override
    public void start(Stage primaryStage) {
        // Main layout
        BorderPane root = new BorderPane();
        root.setStyle("-fx-background-color: linear-gradient(to bottom right, #1a2a3a, #2c3e50);");
        
        // Top: Controls
        VBox controls = createControls();
        root.setTop(controls);
        
        // Center: Animation Canvas
        StackPane animationCanvas = createAnimationCanvas();
        root.setCenter(animationCanvas);
        
        // Bottom: Status
        HBox statusBar = createStatusBar();
        root.setBottom(statusBar);
        
        // Create scene
        Scene scene = new Scene(root, 1000, 700);
        
        // Configure stage
        primaryStage.setTitle("JavaFX Animations & Effects Demo");
        primaryStage.setScene(scene);
        primaryStage.show();
        
        // Start initial animations
        startInitialAnimations();
    }
    
    private VBox createControls() {
        VBox controls = new VBox(15);
        controls.setPadding(new Insets(20));
        controls.setStyle("-fx-background-color: rgba(255, 255, 255, 0.1);");
        
        Label title = new Label("Animation Controls");
        title.setFont(Font.font(24));
        title.setTextFill(Color.WHITE);
        
        // Animation type selector
        HBox typeBox = new HBox(10);
        typeBox.setAlignment(Pos.CENTER_LEFT);
        
        Label typeLabel = new Label("Animation Type:");
        typeLabel.setTextFill(Color.WHITE);
        
        ComboBox animationType = new ComboBox<>();
        animationType.getItems().addAll(
            "Fade", "Translate", "Scale", "Rotate", "Path", "Parallel", "Sequential", "Pulse"
        );
        animationType.setValue("Fade");
        animationType.setPrefWidth(150);
        
        typeBox.getChildren().addAll(typeLabel, animationType);
        
        // Control buttons
        HBox buttonBox = new HBox(10);
        
        Button playBtn = createStyledButton("▶ Play", "#3D8B37");
        Button pauseBtn = createStyledButton("⏸ Pause", "#FF6B35");
        Button stopBtn = createStyledButton("⏹ Stop", "#DC3545");
        Button resetBtn = createStyledButton("↺ Reset", "#00A8E8");
        
        buttonBox.getChildren().addAll(playBtn, pauseBtn, stopBtn, resetBtn);
        
        // Effect selectors
        HBox effectBox = new HBox(10);
        effectBox.setAlignment(Pos.CENTER_LEFT);
        
        Label effectLabel = new Label("Visual Effects:");
        effectLabel.setTextFill(Color.WHITE);
        
        CheckBox glowCheck = new CheckBox("Glow");
        glowCheck.setTextFill(Color.WHITE);
        
        CheckBox shadowCheck = new CheckBox("Drop Shadow");
        shadowCheck.setTextFill(Color.WHITE);
        
        CheckBox blurCheck = new CheckBox("Blur");
        blurCheck.setTextFill(Color.WHITE);
        
        CheckBox reflectionCheck = new CheckBox("Reflection");
        reflectionCheck.setTextFill(Color.WHITE);
        
        effectBox.getChildren().addAll(effectLabel, glowCheck, shadowCheck, blurCheck, reflectionCheck);
        
        // Event handlers
        playBtn.setOnAction(e -> playAnimation(animationType.getValue()));
        pauseBtn.setOnAction(e -> pauseAnimation());
        stopBtn.setOnAction(e -> stopAnimation());
        resetBtn.setOnAction(e -> resetAnimation());
        
        // Effect handlers
        glowCheck.selectedProperty().addListener((obs, oldVal, newVal) -> 
            applyEffect("glow", newVal));
        shadowCheck.selectedProperty().addListener((obs, oldVal, newVal) -> 
            applyEffect("shadow", newVal));
        blurCheck.selectedProperty().addListener((obs, oldVal, newVal) -> 
            applyEffect("blur", newVal));
        reflectionCheck.selectedProperty().addListener((obs, oldVal, newVal) -> 
            applyEffect("reflection", newVal));
        
        controls.getChildren().addAll(title, typeBox, buttonBox, effectBox);
        return controls;
    }
    
    private StackPane createAnimationCanvas() {
        StackPane canvas = new StackPane();
        canvas.setPadding(new Insets(20));
        
        // Create animated shapes
        Rectangle rect = new Rectangle(100, 100, Color.web("#3D8B37", 0.8));
        rect.setArcWidth(20);
        rect.setArcHeight(20);
        rect.setLayoutX(-150);
        
        Circle circle = new Circle(50, Color.web("#FF6B35", 0.8));
        circle.setLayoutX(0);
        circle.setLayoutY(0);
        
        Polygon triangle = new Polygon(0, -50, 50, 50, -50, 50);
        triangle.setFill(Color.web("#00A8E8", 0.8));
        triangle.setLayoutX(150);
        
        // Text label
        Label animatedText = new Label("JavaFX Animations");
        animatedText.setFont(Font.font(28));
        animatedText.setTextFill(Color.WHITE);
        animatedText.setLayoutY(-100);
        
        // Store references for animation
        canvas.getProperties().put("rect", rect);
        canvas.getProperties().put("circle", circle);
        canvas.getProperties().put("triangle", triangle);
        canvas.getProperties().put("text", animatedText);
        
        canvas.getChildren().addAll(rect, circle, triangle, animatedText);
        return canvas;
    }
    
    private HBox createStatusBar() {
        HBox statusBar = new HBox(10);
        statusBar.setPadding(new Insets(10));
        statusBar.setStyle("-fx-background-color: rgba(0, 0, 0, 0.2);");
        statusBar.setAlignment(Pos.CENTER);
        
        Label statusLabel = new Label("Ready");
        statusLabel.setTextFill(Color.WHITE);
        
        ProgressBar animationProgress = new ProgressBar(0);
        animationProgress.setPrefWidth(200);
        
        statusBar.getChildren().addAll(statusLabel, animationProgress);
        return statusBar;
    }
    
    private Button createStyledButton(String text, String color) {
        Button btn = new Button(text);
        btn.setStyle("-fx-background-color: " + color + 
                    "; -fx-text-fill: white; -fx-font-weight: bold;" +
                    " -fx-padding: 10px 20px; -fx-background-radius: 5px;");
        return btn;
    }
    
    private void startInitialAnimations() {
        // Start a gentle pulsing animation on the circle
        Circle circle = (Circle) ((StackPane) ((BorderPane) 
            ((Stage) Stage.getWindows().get(0)).getScene().getRoot())
            .getCenter()).getProperties().get("circle");
        
        pulseTimeline = new Timeline(
            new KeyFrame(Duration.ZERO, 
                new KeyValue(circle.radiusProperty(), 50),
                new KeyValue(circle.opacityProperty(), 0.8)),
            new KeyFrame(Duration.seconds(1), 
                new KeyValue(circle.radiusProperty(), 60),
                new KeyValue(circle.opacityProperty(), 0.6)),
            new KeyFrame(Duration.seconds(2), 
                new KeyValue(circle.radiusProperty(), 50),
                new KeyValue(circle.opacityProperty(), 0.8))
        );
        pulseTimeline.setCycleCount(Timeline.INDEFINITE);
        pulseTimeline.setAutoReverse(true);
        pulseTimeline.play();
    }
    
    private void playAnimation(String type) {
        stopAnimation(); // Stop any ongoing animations
        
        StackPane canvas = (StackPane) ((BorderPane) 
            ((Stage) Stage.getWindows().get(0)).getScene().getRoot())
            .getCenter();
        
        Rectangle rect = (Rectangle) canvas.getProperties().get("rect");
        Circle circle = (Circle) canvas.getProperties().get("circle");
        Polygon triangle = (Polygon) canvas.getProperties().get("triangle");
        Label text = (Label) canvas.getProperties().get("text");
        
        switch (type) {
            case "Fade":
                FadeTransition fade = new FadeTransition(Duration.seconds(2), rect);
                fade.setFromValue(1.0);
                fade.setToValue(0.2);
                fade.setCycleCount(2);
                fade.setAutoReverse(true);
                fade.play();
                break;
                
            case "Translate":
                TranslateTransition translate = new TranslateTransition(Duration.seconds(2), circle);
                translate.setFromX(0);
                translate.setToX(200);
                translate.setCycleCount(2);
                translate.setAutoReverse(true);
                translate.play();
                break;
                
            case "Scale":
                ScaleTransition scale = new ScaleTransition(Duration.seconds(2), triangle);
                scale.setFromX(1);
                scale.setFromY(1);
                scale.setToX(1.5);
                scale.setToY(1.5);
                scale.setCycleCount(2);
                scale.setAutoReverse(true);
                scale.play();
                break;
                
            case "Rotate":
                RotateTransition rotate = new RotateTransition(Duration.seconds(3), rect);
                rotate.setByAngle(360);
                rotate.setCycleCount(2);
                rotate.setAutoReverse(true);
                rotate.play();
                break;
                
            case "Path":
                Path path = new Path();
                path.getElements().add(new MoveTo(0, 0));
                path.getElements().add(new CubicCurveTo(50, -100, 150, 100, 200, 0));
                
                PathTransition pathTransition = new PathTransition();
                pathTransition.setDuration(Duration.seconds(3));
                pathTransition.setPath(path);
                pathTransition.setNode(circle);
                pathTransition.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
                pathTransition.setCycleCount(2);
                pathTransition.setAutoReverse(true);
                pathTransition.play();
                break;
                
            case "Parallel":
                FadeTransition fadeText = new FadeTransition(Duration.seconds(2), text);
                fadeText.setFromValue(0.2);
                fadeText.setToValue(1.0);
                
                TranslateTransition translateText = new TranslateTransition(Duration.seconds(2), text);
                translateText.setFromY(-100);
                translateText.setToY(0);
                
                parallelTransition = new ParallelTransition(fadeText, translateText);
                parallelTransition.setCycleCount(2);
                parallelTransition.setAutoReverse(true);
                parallelTransition.play();
                break;
                
            case "Sequential":
                FadeTransition fade1 = new FadeTransition(Duration.seconds(1), rect);
                fade1.setFromValue(1.0);
                fade1.setToValue(0.2);
                
                FadeTransition fade2 = new FadeTransition(Duration.seconds(1), circle);
                fade2.setFromValue(1.0);
                fade2.setToValue(0.2);
                
                FadeTransition fade3 = new FadeTransition(Duration.seconds(1), triangle);
                fade3.setFromValue(1.0);
                fade3.setToValue(0.2);
                
                sequentialTransition = new SequentialTransition(fade1, fade2, fade3);
                sequentialTransition.setCycleCount(2);
                sequentialTransition.setAutoReverse(true);
                sequentialTransition.play();
                break;
                
            case "Pulse":
                Timeline pulse = new Timeline(
                    new KeyFrame(Duration.ZERO, 
                        new KeyValue(circle.fillProperty(), Color.web("#FF6B35", 0.8))),
                    new KeyFrame(Duration.seconds(0.5), 
                        new KeyValue(circle.fillProperty(), Color.web("#FF8B5D", 1.0))),
                    new KeyFrame(Duration.seconds(1), 
                        new KeyValue(circle.fillProperty(), Color.web("#FF6B35", 0.8)))
                );
                pulse.setCycleCount(Timeline.INDEFINITE);
                pulse.play();
                break;
        }
    }
    
    private void pauseAnimation() {
        if (pulseTimeline != null) {
            pulseTimeline.pause();
        }
        if (parallelTransition != null) {
            parallelTransition.pause();
        }
        if (sequentialTransition != null) {
            sequentialTransition.pause();
        }
    }
    
    private void stopAnimation() {
        if (pulseTimeline != null) {
            pulseTimeline.stop();
        }
        if (parallelTransition != null) {
            parallelTransition.stop();
        }
        if (sequentialTransition != null) {
            sequentialTransition.stop();
        }
    }
    
    private void resetAnimation() {
        stopAnimation();
        
        StackPane canvas = (StackPane) ((BorderPane) 
            ((Stage) Stage.getWindows().get(0)).getScene().getRoot())
            .getCenter();
        
        Rectangle rect = (Rectangle) canvas.getProperties().get("rect");
        Circle circle = (Circle) canvas.getProperties().get("circle");
        Polygon triangle = (Polygon) canvas.getProperties().get("triangle");
        Label text = (Label) canvas.getProperties().get("text");
        
        // Reset positions and properties
        rect.setLayoutX(-150);
        rect.setLayoutY(0);
        rect.setRotate(0);
        rect.setScaleX(1);
        rect.setScaleY(1);
        rect.setOpacity(0.8);
        rect.setEffect(null);
        
        circle.setLayoutX(0);
        circle.setLayoutY(0);
        circle.setTranslateX(0);
        circle.setTranslateY(0);
        circle.setRotate(0);
        circle.setScaleX(1);
        circle.setScaleY(1);
        circle.setOpacity(0.8);
        circle.setEffect(null);
        circle.setFill(Color.web("#FF6B35", 0.8));
        
        triangle.setLayoutX(150);
        triangle.setLayoutY(0);
        triangle.setRotate(0);
        triangle.setScaleX(1);
        triangle.setScaleY(1);
        triangle.setOpacity(0.8);
        triangle.setEffect(null);
        
        text.setLayoutY(-100);
        text.setTranslateY(0);
        text.setOpacity(1.0);
        text.setEffect(null);
        
        // Restart pulse animation
        if (pulseTimeline != null) {
            pulseTimeline.play();
        }
    }
    
    private void applyEffect(String effectType, boolean apply) {
        StackPane canvas = (StackPane) ((BorderPane) 
            ((Stage) Stage.getWindows().get(0)).getScene().getRoot())
            .getCenter();
        
        Circle circle = (Circle) canvas.getProperties().get("circle");
        
        if (apply) {
            switch (effectType) {
                case "glow":
                    circle.setEffect(new Glow(0.8));
                    break;
                case "shadow":
                    circle.setEffect(new DropShadow(10, Color.BLACK));
                    break;
                case "blur":
                    circle.setEffect(new GaussianBlur(10));
                    break;
                case "reflection":
                    Reflection reflection = new Reflection();
                    reflection.setFraction(0.7);
                    circle.setEffect(reflection);
                    break;
            }
        } else {
            circle.setEffect(null);
        }
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}
Animation Types
  • Timeline: Keyframe-based animations
  • Transition: Predefined animations
  • ParallelTransition: Multiple animations simultaneously
  • SequentialTransition: Animations in sequence
  • PathTransition: Follow a path
  • Fade/Rotate/Scale/Translate: Specific transitions
Visual Effects
  • DropShadow: Cast shadow effect
  • InnerShadow: Inner shadow effect
  • Glow: Glowing edges
  • Bloom: Bright blooming effect
  • GaussianBlur: Blur effect
  • Reflection: Mirror reflection
  • Lighting: 3D lighting effect

6. Charts & 3D Graphics

Charts3DDemo.java
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Point3D;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.chart.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import java.util.Random;

public class Charts3DDemo extends Application {
    
    private PerspectiveCamera camera;
    private Rotate rotateX = new Rotate(0, Rotate.X_AXIS);
    private Rotate rotateY = new Rotate(0, Rotate.Y_AXIS);
    private double mousePosX, mousePosY;
    
    @Override
    public void start(Stage primaryStage) {
        // Main layout with tabs
        TabPane tabPane = new TabPane();
        
        // Tab 1: 2D Charts
        Tab chartsTab = new Tab("2D Charts", createChartsPane());
        chartsTab.setClosable(false);
        
        // Tab 2: 3D Graphics
        Tab threeDTab = new Tab("3D Graphics", create3DPane());
        threeDTab.setClosable(false);
        
        tabPane.getTabs().addAll(chartsTab, threeDTab);
        
        // Create scene
        Scene scene = new Scene(tabPane, 1200, 800);
        
        // Configure stage
        primaryStage.setTitle("JavaFX Charts & 3D Graphics Demo");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private BorderPane createChartsPane() {
        BorderPane pane = new BorderPane();
        pane.setPadding(new Insets(20));
        pane.setStyle("-fx-background-color: #f8f9fa;");
        
        // Top: Controls
        VBox controls = createChartControls();
        pane.setTop(controls);
        
        // Center: Charts grid
        GridPane chartsGrid = new GridPane();
        chartsGrid.setHgap(20);
        chartsGrid.setVgap(20);
        chartsGrid.setPadding(new Insets(20));
        
        // Row 1: Line Chart & Bar Chart
        VBox lineChartBox = createLineChart();
        VBox barChartBox = createBarChart();
        chartsGrid.add(lineChartBox, 0, 0);
        chartsGrid.add(barChartBox, 1, 0);
        
        // Row 2: Pie Chart & Area Chart
        VBox pieChartBox = createPieChart();
        VBox areaChartBox = createAreaChart();
        chartsGrid.add(pieChartBox, 0, 1);
        chartsGrid.add(areaChartBox, 1, 1);
        
        pane.setCenter(chartsGrid);
        
        return pane;
    }
    
    private VBox createChartControls() {
        VBox controls = new VBox(15);
        controls.setPadding(new Insets(10));
        controls.setStyle("-fx-background-color: white; -fx-background-radius: 8px;");
        
        Label title = new Label("Chart Controls");
        title.setStyle("-fx-font-size: 18px; -fx-font-weight: bold; -fx-text-fill: #3D8B37;");
        
        HBox buttonBox = new HBox(10);
        Button refreshBtn = new Button("Refresh Data");
        refreshBtn.setStyle("-fx-background-color: #3D8B37; -fx-text-fill: white;");
        
        Button exportBtn = new Button("Export Chart");
        exportBtn.setStyle("-fx-background-color: #00A8E8; -fx-text-fill: white;");
        
        ComboBox themeCombo = new ComboBox<>();
        themeCombo.getItems().addAll("Default", "Dark", "Colorful", "Monochrome");
        themeCombo.setValue("Default");
        themeCombo.setPromptText("Select Theme");
        
        buttonBox.getChildren().addAll(refreshBtn, exportBtn, themeCombo);
        
        controls.getChildren().addAll(title, buttonBox);
        return controls;
    }
    
    private VBox createLineChart() {
        VBox chartBox = new VBox(10);
        chartBox.setPadding(new Insets(15));
        chartBox.setStyle("-fx-background-color: white; -fx-background-radius: 8px;");
        
        Label title = new Label("Monthly Sales Trend");
        title.setStyle("-fx-font-weight: bold;");
        
        // Define X and Y axis
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();
        yAxis.setLabel("Sales ($)");
        
        // Create line chart
        final LineChart lineChart = new LineChart<>(xAxis, yAxis);
        lineChart.setTitle("2024 Sales Performance");
        lineChart.setLegendVisible(true);
        lineChart.setPrefSize(400, 300);
        
        // Series 1: Product A
        XYChart.Series series1 = new XYChart.Series<>();
        series1.setName("Product A");
        series1.getData().addAll(
            new XYChart.Data<>("Jan", 23000),
            new XYChart.Data<>("Feb", 28000),
            new XYChart.Data<>("Mar", 32000),
            new XYChart.Data<>("Apr", 31000),
            new XYChart.Data<>("May", 35000),
            new XYChart.Data<>("Jun", 42000)
        );
        
        // Series 2: Product B
        XYChart.Series series2 = new XYChart.Series<>();
        series2.setName("Product B");
        series2.getData().addAll(
            new XYChart.Data<>("Jan", 18000),
            new XYChart.Data<>("Feb", 21000),
            new XYChart.Data<>("Mar", 25000),
            new XYChart.Data<>("Apr", 29000),
            new XYChart.Data<>("May", 33000),
            new XYChart.Data<>("Jun", 38000)
        );
        
        // Series 3: Product C
        XYChart.Series series3 = new XYChart.Series<>();
        series3.setName("Product C");
        series3.getData().addAll(
            new XYChart.Data<>("Jan", 12000),
            new XYChart.Data<>("Feb", 15000),
            new XYChart.Data<>("Mar", 18000),
            new XYChart.Data<>("Apr", 22000),
            new XYChart.Data<>("May", 26000),
            new XYChart.Data<>("Jun", 30000)
        );
        
        lineChart.getData().addAll(series1, series2, series3);
        
        // Style the chart
        lineChart.lookup(".chart-plot-background").setStyle("-fx-background-color: transparent;");
        
        chartBox.getChildren().addAll(title, lineChart);
        return chartBox;
    }
    
    private VBox createBarChart() {
        VBox chartBox = new VBox(10);
        chartBox.setPadding(new Insets(15));
        chartBox.setStyle("-fx-background-color: white; -fx-background-radius: 8px;");
        
        Label title = new Label("Quarterly Revenue by Region");
        title.setStyle("-fx-font-weight: bold;");
        
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();
        
        final BarChart barChart = new BarChart<>(xAxis, yAxis);
        barChart.setTitle("Regional Performance");
        barChart.setLegendVisible(true);
        barChart.setPrefSize(400, 300);
        
        // Q1 Data
        XYChart.Series q1Series = new XYChart.Series<>();
        q1Series.setName("Q1");
        q1Series.getData().addAll(
            new XYChart.Data<>("North", 45000),
            new XYChart.Data<>("South", 38000),
            new XYChart.Data<>("East", 42000),
            new XYChart.Data<>("West", 39000)
        );
        
        // Q2 Data
        XYChart.Series q2Series = new XYChart.Series<>();
        q2Series.setName("Q2");
        q2Series.getData().addAll(
            new XYChart.Data<>("North", 52000),
            new XYChart.Data<>("South", 45000),
            new XYChart.Data<>("East", 48000),
            new XYChart.Data<>("West", 46000)
        );
        
        // Q3 Data
        XYChart.Series q3Series = new XYChart.Series<>();
        q3Series.setName("Q3");
        q3Series.getData().addAll(
            new XYChart.Data<>("North", 58000),
            new XYChart.Data<>("South", 51000),
            new XYChart.Data<>("East", 55000),
            new XYChart.Data<>("West", 53000)
        );
        
        barChart.getData().addAll(q1Series, q2Series, q3Series);
        
        chartBox.getChildren().addAll(title, barChart);
        return chartBox;
    }
    
    private VBox createPieChart() {
        VBox chartBox = new VBox(10);
        chartBox.setPadding(new Insets(15));
        chartBox.setStyle("-fx-background-color: white; -fx-background-radius: 8px;");
        
        Label title = new Label("Market Share Distribution");
        title.setStyle("-fx-font-weight: bold;");
        
        ObservableList pieChartData = FXCollections.observableArrayList(
            new PieChart.Data("Company A", 35),
            new PieChart.Data("Company B", 25),
            new PieChart.Data("Company C", 20),
            new PieChart.Data("Company D", 12),
            new PieChart.Data("Others", 8)
        );
        
        final PieChart pieChart = new PieChart(pieChartData);
        pieChart.setTitle("Market Share 2024");
        pieChart.setLabelsVisible(true);
        pieChart.setLegendVisible(true);
        pieChart.setPrefSize(400, 300);
        pieChart.setStartAngle(90); // Start at top
        
        // Add hover effects
        for (PieChart.Data data : pieChartData) {
            data.getNode().setOnMouseEntered(e -> {
                data.getNode().setScaleX(1.1);
                data.getNode().setScaleY(1.1);
            });
            data.getNode().setOnMouseExited(e -> {
                data.getNode().setScaleX(1.0);
                data.getNode().setScaleY(1.0);
            });
        }
        
        chartBox.getChildren().addAll(title, pieChart);
        return chartBox;
    }
    
    private VBox createAreaChart() {
        VBox chartBox = new VBox(10);
        chartBox.setPadding(new Insets(15));
        chartBox.setStyle("-fx-background-color: white; -fx-background-radius: 8px;");
        
        Label title = new Label("Website Traffic Analysis");
        title.setStyle("-fx-font-weight: bold;");
        
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();
        
        final AreaChart areaChart = new AreaChart<>(xAxis, yAxis);
        areaChart.setTitle("Daily Visitors");
        areaChart.setLegendVisible(true);
        areaChart.setPrefSize(400, 300);
        
        XYChart.Series desktopSeries = new XYChart.Series<>();
        desktopSeries.setName("Desktop");
        desktopSeries.getData().addAll(
            new XYChart.Data<>("Mon", 4500),
            new XYChart.Data<>("Tue", 5200),
            new XYChart.Data<>("Wed", 4800),
            new XYChart.Data<>("Thu", 5100),
            new XYChart.Data<>("Fri", 4900),
            new XYChart.Data<>("Sat", 3800),
            new XYChart.Data<>("Sun", 3200)
        );
        
        XYChart.Series mobileSeries = new XYChart.Series<>();
        mobileSeries.setName("Mobile");
        mobileSeries.getData().addAll(
            new XYChart.Data<>("Mon", 3800),
            new XYChart.Data<>("Tue", 4200),
            new XYChart.Data<>("Wed", 4100),
            new XYChart.Data<>("Thu", 4500),
            new XYChart.Data<>("Fri", 4300),
            new XYChart.Data<>("Sat", 5200),
            new XYChart.Data<>("Sun", 4800)
        );
        
        areaChart.getData().addAll(desktopSeries, mobileSeries);
        
        chartBox.getChildren().addAll(title, areaChart);
        return chartBox;
    }
    
    private BorderPane create3DPane() {
        BorderPane pane = new BorderPane();
        pane.setPadding(new Insets(20));
        pane.setStyle("-fx-background-color: #1a2a3a;");
        
        // Top: Controls
        HBox controls = create3DControls();
        pane.setTop(controls);
        
        // Center: 3D Scene
        SubScene subScene = create3DScene();
        pane.setCenter(subScene);
        
        return pane;
    }
    
    private HBox create3DControls() {
        HBox controls = new HBox(15);
        controls.setPadding(new Insets(10));
        controls.setStyle("-fx-background-color: rgba(255, 255, 255, 0.1); -fx-background-radius: 8px;");
        controls.setAlignment(Pos.CENTER_LEFT);
        
        Label title = new Label("3D Scene Controls");
        title.setStyle("-fx-font-size: 18px; -fx-font-weight: bold; -fx-text-fill: white;");
        
        Button rotateBtn = new Button("Auto Rotate");
        rotateBtn.setStyle("-fx-background-color: #3D8B37; -fx-text-fill: white;");
        
        Button resetBtn = new Button("Reset View");
        resetBtn.setStyle("-fx-background-color: #00A8E8; -fx-text-fill: white;");
        
        Label instruction = new Label("Drag to rotate • Scroll to zoom");
        instruction.setStyle("-fx-text-fill: #aaa; -fx-font-style: italic;");
        
        controls.getChildren().addAll(title, rotateBtn, resetBtn, instruction);
        return controls;
    }
    
    private SubScene create3DScene() {
        // Create 3D group
        Group root3D = new Group();
        
        // Create camera
        camera = new PerspectiveCamera(true);
        camera.setNearClip(0.1);
        camera.setFarClip(10000.0);
        camera.setTranslateZ(-1000);
        
        // Add transforms for mouse control
        root3D.getTransforms().addAll(rotateX, rotateY);
        
        // Create 3D objects
        create3DObjects(root3D);
        
        // Create subscene
        SubScene subScene = new SubScene(root3D, 800, 600, true, SceneAntialiasing.BALANCED);
        subScene.setCamera(camera);
        subScene.setFill(Color.rgb(30, 40, 50));
        
        // Add mouse controls
        setupMouseControls(subScene, root3D);
        
        return subScene;
    }
    
    private void create3DObjects(Group root) {
        // Create a 3D cube
        Box cube = new Box(200, 200, 200);
        cube.setTranslateX(-300);
        cube.setMaterial(new PhongMaterial(Color.RED));
        cube.setDrawMode(DrawMode.FILL);
        
        // Create a sphere
        Sphere sphere = new Sphere(120);
        sphere.setTranslateX(0);
        sphere.setMaterial(new PhongMaterial(Color.BLUE));
        
        // Create a cylinder
        Cylinder cylinder = new Cylinder(80, 200);
        cylinder.setTranslateX(300);
        cylinder.setMaterial(new PhongMaterial(Color.GREEN));
        
        // Create a pyramid (custom mesh)
        MeshView pyramid = createPyramid(150, 200);
        pyramid.setTranslateX(-300);
        pyramid.setTranslateY(300);
        pyramid.setMaterial(new PhongMaterial(Color.ORANGE));
        
        // Create a torus (donut)
        MeshView torus = createTorus(100, 40);
        torus.setTranslateX(0);
        torus.setTranslateY(300);
        torus.setMaterial(new PhongMaterial(Color.PURPLE));
        
        // Create a cone
        Cone cone = new Cone(100, 200);
        cone.setTranslateX(300);
        cone.setTranslateY(300);
        cone.setMaterial(new PhongMaterial(Color.YELLOW));
        
        // Add lighting
        PointLight pointLight = new PointLight(Color.WHITE);
        pointLight.setTranslateX(-500);
        pointLight.setTranslateY(-500);
        pointLight.setTranslateZ(-500);
        
        AmbientLight ambientLight = new AmbientLight(Color.rgb(50, 50, 50));
        
        // Add grid floor
        Group grid = createGrid(1000, 1000, 50);
        grid.setTranslateY(200);
        
        // Add all objects to root
        root.getChildren().addAll(cube, sphere, cylinder, pyramid, torus, cone, grid, pointLight, ambientLight);
    }
    
    private MeshView createPyramid(double size, double height) {
        float[] points = {
            // Base vertices
            (float)-size, 0, (float)-size,
            (float)size, 0, (float)-size,
            (float)size, 0, (float)size,
            (float)-size, 0, (float)size,
            // Apex
            0, (float)-height, 0
        };
        
        int[] faces = {
            // Base
            0, 0, 1, 0, 2, 0,
            0, 0, 2, 0, 3, 0,
            // Sides
            0, 0, 4, 0, 1, 0,
            1, 0, 4, 0, 2, 0,
            2, 0, 4, 0, 3, 0,
            3, 0, 4, 0, 0, 0
        };
        
        TriangleMesh mesh = new TriangleMesh();
        mesh.getPoints().addAll(points);
        mesh.getFaces().addAll(faces);
        
        return new MeshView(mesh);
    }
    
    private MeshView createTorus(double radius, double tubeRadius) {
        final int divR = 32;
        final int divT = 24;
        
        TriangleMesh mesh = new TriangleMesh();
        
        // Create vertices
        for (int i = 0; i <= divR; i++) {
            double r = 2 * Math.PI * i / divR;
            double cosR = Math.cos(r);
            double sinR = Math.sin(r);
            
            for (int j = 0; j <= divT; j++) {
                double t = 2 * Math.PI * j / divT;
                double cosT = Math.cos(t);
                double sinT = Math.sin(t);
                
                float x = (float)((radius + tubeRadius * cosT) * cosR);
                float y = (float)((radius + tubeRadius * cosT) * sinR);
                float z = (float)(tubeRadius * sinT);
                
                mesh.getPoints().addAll(x, y, z);
            }
        }
        
        // Create faces
        for (int i = 0; i < divR; i++) {
            for (int j = 0; j < divT; j++) {
                int p0 = i * (divT + 1) + j;
                int p1 = p0 + 1;
                int p2 = p0 + (divT + 1);
                int p3 = p2 + 1;
                
                mesh.getFaces().addAll(p0, 0, p2, 0, p1, 0);
                mesh.getFaces().addAll(p2, 0, p3, 0, p1, 0);
            }
        }
        
        return new MeshView(mesh);
    }
    
    private Group createGrid(double size, double spacing, int divisions) {
        Group grid = new Group();
        
        // Create grid lines
        for (int i = -divisions; i <= divisions; i++) {
            double position = i * spacing;
            
            // Horizontal lines
            Line hLine = new Line(-size, position, size, position);
            hLine.setStroke(Color.rgb(100, 100, 100, 0.3));
            hLine.setStrokeWidth(1);
            
            // Vertical lines
            Line vLine = new Line(position, -size, position, size);
            vLine.setStroke(Color.rgb(100, 100, 100, 0.3));
            vLine.setStrokeWidth(1);
            
            grid.getChildren().addAll(hLine, vLine);
        }
        
        // Center lines
        Line centerX = new Line(-size, 0, size, 0);
        centerX.setStroke(Color.rgb(200, 200, 200, 0.5));
        centerX.setStrokeWidth(2);
        
        Line centerY = new Line(0, -size, 0, size);
        centerY.setStroke(Color.rgb(200, 200, 200, 0.5));
        centerY.setStrokeWidth(2);
        
        grid.getChildren().addAll(centerX, centerY);
        
        return grid;
    }
    
    private void setupMouseControls(SubScene subScene, Group root3D) {
        subScene.setOnMousePressed(event -> {
            mousePosX = event.getSceneX();
            mousePosY = event.getSceneY();
        });
        
        subScene.setOnMouseDragged(event -> {
            double deltaX = event.getSceneX() - mousePosX;
            double deltaY = event.getSceneY() - mousePosY;
            
            rotateX.setAngle(rotateX.getAngle() - deltaY * 0.5);
            rotateY.setAngle(rotateY.getAngle() + deltaX * 0.5);
            
            mousePosX = event.getSceneX();
            mousePosY = event.getSceneY();
        });
        
        subScene.setOnScroll(event -> {
            double deltaZ = event.getDeltaY() * 10;
            camera.setTranslateZ(camera.getTranslateZ() + deltaZ);
        });
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}
Chart Type Class Best For Features
Line Chart LineChart Trends over time Multiple series, data points, tooltips
Bar Chart BarChart Comparing categories Stacked bars, grouped bars, colors
Pie Chart PieChart Proportions/percentages Interactive slices, legends, tooltips
Area Chart AreaChart Cumulative data Stacked areas, gradient fills
Scatter Chart ScatterChart Correlations Data point clusters, regression lines
Bubble Chart BubbleChart 3D data visualization Variable bubble sizes, colors

7. Best Practices & Performance

Common JavaFX Mistakes:
  1. Blocking JavaFX Thread: Performing long operations on UI thread
  2. Memory Leaks: Not removing listeners and bindings
  3. Overusing Animations: Too many animations causing performance issues
  4. Poor CSS Organization: Inline styles instead of CSS files
  5. Ignoring FXML: Writing all UI in code instead of FXML
  6. Not Using Properties: Missing data binding opportunities
JavaFX Best Practices
  • Always use FXML for UI layout
  • Separate CSS styles from Java code
  • Use Properties and Bindings for data synchronization
  • Implement Model-View-Controller (MVC) pattern
  • Use Task/Service for background operations
  • Optimize Scene Graph (minimize nodes, use Canvas for complex drawings)
  • Implement proper error handling and user feedback
Performance Tips
  • Use Canvas: For complex, dynamic drawings instead of many nodes
  • Cache nodes: node.setCache(true) for static content
  • Lazy loading: Load complex UI parts on demand
  • Virtualized controls: Use ListView/TableView with cell factories
  • Batch updates: Use Platform.runLater() for UI updates
  • Monitor memory: Use VisualVM or Java Mission Control
  • Test on target hardware: Different GPUs perform differently

Key Takeaways

  • JavaFX is the modern replacement for Swing
  • FXML & Scene Builder enable separation of UI and logic
  • CSS Styling provides professional-looking interfaces
  • Properties & Bindings simplify data synchronization
  • Animations & Effects create engaging user experiences
  • Charts & 3D enable advanced data visualization
  • Performance optimization is crucial for complex applications
Feature JavaFX Swing Modern Web
Rendering Hardware Accelerated CPU-based GPU Accelerated
Styling CSS Look & Feel CSS
Layout FXML/Scene Builder Code/Matisse HTML/CSS
Performance Excellent Poor Good (depends)
3D Support Built-in None WebGL
Deployment Native/JNLP JAR/Web Start Web Server