Java GUI Applications

"Java's Swing library makes it possible to build fully interactive desktop applications with buttons, text fields, labels, and more — all connected through Java's event-driven programming model."- Claude 2026

Developing a GUI Application Introduction

So far we've built console applications — programs that take input and produce output as plain text. A Graphical User Interface (GUI) application instead presents the user with visual elements: windows, buttons, text fields, and labels that they can interact with using a mouse and keyboard.

Java's Swing library provides all the components needed to build desktop GUI applications. Swing is part of the Java standard library, so no additional installation is required. Every GUI application starts with a window, and in Swing that window is called a JFrame.

Constructor Review

Before building a GUI, it helps to revisit constructors. A constructor is a special method that runs automatically when an object is created with new. It has the same name as the class and no return type. Constructors are the ideal place to set up a GUI — creating the window, adding components, and configuring layout all happen there.

Without a constructor:

Attributes start with default values (null, 0, etc.) and must be set manually after creating the object.

With a constructor:

The object is fully initialized the moment it's created — perfect for setting up a window that should be ready to display immediately.

public class Character {

    private String name;
    private int health;

    // Constructor: runs automatically when a Character is created
    public Character(String name, int health) {
        this.name = name;
        this.health = health;
        System.out.println(name + " created with " + health + " health.");
    }

    public static void main(String[] args) {
        // No need to call setName/setHealth separately
        Character player1 = new Character("Hero", 100);
        Character player2 = new Character("Villain", 80);
    }

}
Hero created with 100 health.
Villain created with 80 health.
TIP: If you define a constructor with parameters, Java removes the default no-argument constructor. If you still need to create objects without arguments, add a second constructor with no parameters.
Graphical User Interface (GUI)

A GUI application is built by creating a JFrame (the window) and adding components to it — things like labels, buttons, and text fields. The user interacts with these components, and the program responds through event listeners.

The core classes we'll use all come from the javax.swing package, which must be imported at the top of your file.

Core Swing Components

JFrame

The main application window. Everything else is placed inside the JFrame. You set its size, title, and what happens when the user closes it.

JPanel

An invisible container used to group and organize other components. Panels can be nested inside other panels for complex layouts.

JLabel

Displays a line of text or an image. Labels are not interactive — they are used to describe other components or display output.

JTextField

A single-line text box where the user can type input. You can read its contents with getText() and set it with setText().

JButton

A clickable button. When clicked, it triggers an ActionListener — the piece of code that responds to the event.

Main Method Commands

In a GUI application, the main method has one job: launch the application. It creates an instance of your GUI class, which triggers the constructor, which builds and displays the window. Swing requires that GUI creation happen on the Event Dispatch Thread (EDT) — a dedicated thread for all UI operations. The SwingUtilities.invokeLater() call ensures this.

public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> new MyApp());
}

The () -> new MyApp() syntax is a lambda expression — a compact way to pass a small piece of code as an argument. Here it tells invokeLater to create a new MyApp object on the EDT when the application starts.

GUI Components

Components are declared as instance variables so they can be accessed throughout the class — by the constructor that creates them and by the event listeners that interact with them later.

Example: Declaring and Adding Components
import javax.swing.*;

public class MyApp extends JFrame {

    // Declare components as instance variables
    private JLabel nameLabel;
    private JTextField nameField;
    private JButton greetButton;
    private JLabel outputLabel;

    public MyApp() {
        // Window settings
        setTitle("Greeting App");
        setSize(400, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Create components
        nameLabel   = new JLabel("Enter your name:");
        nameField   = new JTextField(15);
        greetButton = new JButton("Greet");
        outputLabel = new JLabel(" ");

        // Add components to the window
        add(nameLabel);
        add(nameField);
        add(greetButton);
        add(outputLabel);

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new MyApp());
    }

}
TIP: setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) ensures the program terminates when the user closes the window. Without it, the window closes but the Java process keeps running in the background.
Layout Managers and JFrame Components

By default, JFrame uses a BorderLayout, which divides the window into five regions: North, South, East, West, and Center. For beginners, FlowLayout is simpler — it places components side by side, left to right, wrapping to the next line when needed. GridLayout arranges components in a fixed rows-and-columns grid.

import javax.swing.*;
import java.awt.*;

public class MyApp extends JFrame {

    private JLabel nameLabel;
    private JTextField nameField;
    private JButton greetButton;
    private JLabel outputLabel;

    public MyApp() {
        setTitle("Greeting App");
        setSize(400, 150);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // FlowLayout places components left to right
        setLayout(new FlowLayout());

        nameLabel   = new JLabel("Enter your name:");
        nameField   = new JTextField(15);
        greetButton = new JButton("Greet");
        outputLabel = new JLabel(" ");

        add(nameLabel);
        add(nameField);
        add(greetButton);
        add(outputLabel);

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new MyApp());
    }

}
Event-Driven Programming and Handlers

In a GUI application, the program waits for the user to do something — click a button, type in a field — and then responds. This is called event-driven programming. The code that responds to an event is called an event handler, and it is registered using an ActionListener.

You attach an ActionListener to a component using addActionListener(). When the event occurs, Java calls the actionPerformed method automatically.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class MyApp extends JFrame {

    private JLabel nameLabel;
    private JTextField nameField;
    private JButton greetButton;
    private JLabel outputLabel;

    public MyApp() {
        setTitle("Greeting App");
        setSize(400, 150);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        nameLabel   = new JLabel("Enter your name:");
        nameField   = new JTextField(15);
        greetButton = new JButton("Greet");
        outputLabel = new JLabel(" ");

        // Attach an event handler to the button
        greetButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String name = nameField.getText();
                outputLabel.setText("Hello, " + name + "!");
            }
        });

        add(nameLabel);
        add(nameField);
        add(greetButton);
        add(outputLabel);

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new MyApp());
    }

}

When the user types a name and clicks Greet, actionPerformed fires: it reads the text field with getText() and updates the label with setText().

User Input and Input Errors

When reading user input from a JTextField, the value comes back as a String. If your program expects a number, you need to convert it using Integer.parseInt() or Double.parseDouble(). If the user types something that isn't a valid number, this throws a NumberFormatException — which you can catch with a try/catch block to display a helpful error message instead of crashing.

greetButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        try {
            int age = Integer.parseInt(nameField.getText());
            outputLabel.setText("You are " + age + " years old.");
        } catch (NumberFormatException ex) {
            outputLabel.setText("Please enter a valid number.");
        }
    }
});
Complete GUI Application
This complete example brings everything together with a polished game-themed UI. It uses a dark background panel, custom colors, a JProgressBar that changes color as health drops, and BoxLayout with spacing for a clean layout. Enter a damage value and click Attack to see it in action.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;

public class CharacterGUI extends JFrame {

    private int health = 100;
    private int maxHealth = 100;

    private JLabel titleLabel;
    private JLabel statusLabel;
    private JProgressBar healthBar;
    private JLabel damageLabel;
    private JTextField damageField;
    private JButton attackButton;
    private JLabel outputLabel;

    public CharacterGUI() {
        setTitle("Character Health Tracker");
        setSize(420, 280);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);

        // Main panel with padding and dark background
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
        mainPanel.setBackground(new Color(40, 40, 55));
        mainPanel.setBorder(new EmptyBorder(20, 30, 20, 30));

        // Title
        titleLabel = new JLabel("⚔  Hero's Quest");
        titleLabel.setFont(new Font("Serif", Font.BOLD, 22));
        titleLabel.setForeground(new Color(220, 180, 80));
        titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT);

        // Health status label
        statusLabel = new JLabel("Hero Health: " + health + " / " + maxHealth);
        statusLabel.setFont(new Font("SansSerif", Font.PLAIN, 14));
        statusLabel.setForeground(Color.WHITE);
        statusLabel.setAlignmentX(Component.CENTER_ALIGNMENT);

        // Health progress bar
        healthBar = new JProgressBar(0, maxHealth);
        healthBar.setValue(health);
        healthBar.setForeground(new Color(80, 200, 100));
        healthBar.setBackground(new Color(60, 60, 75));
        healthBar.setMaximumSize(new Dimension(360, 18));
        healthBar.setBorder(new EmptyBorder(0, 0, 0, 0));

        // Input row panel
        JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0));
        inputPanel.setBackground(new Color(40, 40, 55));
        inputPanel.setMaximumSize(new Dimension(360, 40));

        damageLabel = new JLabel("Damage:");
        damageLabel.setForeground(Color.LIGHT_GRAY);
        damageLabel.setFont(new Font("SansSerif", Font.PLAIN, 13));

        damageField = new JTextField(8);
        damageField.setFont(new Font("SansSerif", Font.PLAIN, 13));

        attackButton = new JButton("Attack!");
        attackButton.setBackground(new Color(180, 60, 60));
        attackButton.setForeground(Color.WHITE);
        attackButton.setFont(new Font("SansSerif", Font.BOLD, 13));
        attackButton.setFocusPainted(false);
        attackButton.setBorder(new EmptyBorder(6, 16, 6, 16));

        inputPanel.add(damageLabel);
        inputPanel.add(damageField);
        inputPanel.add(attackButton);

        // Output label
        outputLabel = new JLabel(" ");
        outputLabel.setFont(new Font("SansSerif", Font.ITALIC, 13));
        outputLabel.setForeground(new Color(180, 180, 220));
        outputLabel.setAlignmentX(Component.CENTER_ALIGNMENT);

        // Attach event handler
        attackButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    int damage = Integer.parseInt(damageField.getText());
                    health -= damage;
                    if (health < 0) health = 0;
                    statusLabel.setText("Hero Health: " + health + " / " + maxHealth);
                    healthBar.setValue(health);
                    // Change bar color based on health level
                    if (health > 60) {
                        healthBar.setForeground(new Color(80, 200, 100));
                    } else if (health > 25) {
                        healthBar.setForeground(new Color(230, 180, 50));
                    } else {
                        healthBar.setForeground(new Color(200, 60, 60));
                    }
                    if (health <= 0) {
                        outputLabel.setText("Hero has been defeated!");
                        attackButton.setEnabled(false);
                    } else {
                        outputLabel.setText("Hero took " + damage + " damage!");
                    }
                } catch (NumberFormatException ex) {
                    outputLabel.setText("Please enter a valid number.");
                }
            }
        });

        // Add components with spacing
        mainPanel.add(titleLabel);
        mainPanel.add(Box.createVerticalStrut(12));
        mainPanel.add(statusLabel);
        mainPanel.add(Box.createVerticalStrut(6));
        mainPanel.add(healthBar);
        mainPanel.add(Box.createVerticalStrut(16));
        mainPanel.add(inputPanel);
        mainPanel.add(Box.createVerticalStrut(10));
        mainPanel.add(outputLabel);

        add(mainPanel);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new CharacterGUI());
    }

}
Running the Application

Unlike console programs, a Swing GUI requires a local display to run. Below are two ways to run this on your own machine.

Method 1: Using an IDE

IntelliJ IDEA and Eclipse both support Java Swing out of the box. Create a new Java project, paste the code into a file named CharacterGUI.java, and click Run. The GUI window will appear automatically.

Method 2: Text Editor + Terminal

This is what an IDE does behind the scenes. You need the JDK installed first, then just two commands.

  1. Download and install the Java Development Kit (JDK) from Oracle.
  2. Save the code above in a file named CharacterGUI.java.
  3. Open a terminal in the same folder and compile:
    javac CharacterGUI.java
  4. Run the compiled program:
    java CharacterGUI

The GUI window will open on your screen. The javac command compiles your source code into bytecode, and java runs it on the JVM — exactly what an IDE does when you click Run.

→ This page was created with help from Gemini and Claude AI.