"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
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.
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.
new
Attributes start with default values (null, 0, etc.) and must be set manually after creating the object.
null
0
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.
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.
javax.swing
The main application window. Everything else is placed inside the JFrame. You set its size, title, and what happens when the user closes it.
An invisible container used to group and organize other components. Panels can be nested inside other panels for complex layouts.
Displays a line of text or an image. Labels are not interactive — they are used to describe other components or display output.
A single-line text box where the user can type input. You can read its contents with getText() and set it with setText().
getText()
setText()
A clickable button. When clicked, it triggers an ActionListener — the piece of code that responds to the event.
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.
main
SwingUtilities.invokeLater()
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.
() -> new MyApp()
invokeLater
MyApp
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.
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()); } }
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
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()); } }
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.
addActionListener()
actionPerformed
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().
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.
JTextField
Integer.parseInt()
Double.parseDouble()
try/catch
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."); } } });
JProgressBar
BoxLayout
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()); } }
Unlike console programs, a Swing GUI requires a local display to run. Below are two ways to run this on your own machine.
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.
CharacterGUI.java
This is what an IDE does behind the scenes. You need the JDK installed first, then just two commands.
javac CharacterGUI.java
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.
javac
java