Skip to Content
Course content

215: An Overview of Swing for Legacy Applications

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've spent the last few mornings digging through a codebase for a client that hasn't been touched since 2008. It's a massive internal tool for managing server clusters, and it's built entirely on Swing. If you've only worked with modern web frameworks or JavaFX, Swing feels like stepping into a time machine. It's clunky, the default look is "Windows 95 grey," but it's incredibly stable. Since you'll likely run into this in any enterprise environment, let's walk through how it actually works by trying to recreate a piece of that server monitor.

Getting a Window on Screen

First, I wanted to see how easy it is to just get a basic window up. I'll start with a JFrame—that's the top-level container in Swing. I'll throw a button in there to simulate a "Connect to Server" action.

import javax.swing.*;

public class ServerMonitor {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Legacy Server Monitor");
        JButton connectBtn = new JButton("Connect to Server");
        
        frame.add(connectBtn); 
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

When I ran this, I noticed something weird. The button didn't just sit in the middle; it stretched to fill the entire window. It looked absurd. I forgot that JFrame uses a BorderLayout by default. When you call add() without specifying a position, Swing just dumps the component into the "Center" region, and BorderLayout expands the center component to fill all available space.

Fighting with the Layout

I don't want one giant button. I want a label and a button side-by-side. To fix the stretching issue, I need a different layout manager. Most of us instinctively want to use absolute positioning (X, Y coordinates), but in Swing, that's a recipe for disaster because your UI will break the second someone resizes the window or opens it on a screen with a different DPI.

Instead, I'll use a JPanel with a FlowLayout. A JPanel is basically a generic container that I can stick inside the frame. I'll put the label and button inside the panel, and then put the panel inside the frame.

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

public class ServerMonitor {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Legacy Server Monitor");
        
        // Create a panel with FlowLayout (default for JPanel)
        JPanel panel = new JPanel(); 
        JLabel statusLabel = new JLabel("Status: Disconnected");
        JButton connectBtn = new JButton("Connect");

        panel.add(statusLabel);
        panel.add(connectBtn);

        frame.add(panel); // Now the panel is in the Center, but components inside flow naturally
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

That's better. The components now respect their preferred size and wrap like text in a document. If I wanted the status label at the top and the buttons at the bottom, I'd probably use a combination of BorderLayout for the frame (putting a panel in NORTH and another in SOUTH). It's like building with LEGOs, but the blocks are sometimes stubborn.

The UI Freeze Mystery

Now, here is where most developers trip up with Swing. I wanted the "Connect" button to simulate a network call. I added an ActionListener that sleeps for two seconds to mimic a server response, then updates the label.

connectBtn.addActionListener(e -> {
    try {
        Thread.sleep(2000); // Simulate network lag
        statusLabel.setText("Status: Connected!");
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
});

When I clicked the button, the entire application froze. The window became unresponsive, I couldn't move it, and the label didn't update until after the two seconds were up. This happened because Swing is single-threaded. Everything—painting the window, handling clicks, updating text—happens on the Event Dispatch Thread (EDT). By calling Thread.sleep() inside the listener, I effectively told the UI thread to stop breathing for two seconds.

To fix this, I have to run the heavy lifting in a separate thread, but there's a catch: you are not allowed to update Swing components from any thread other than the EDT. If you do, you'll get random race conditions and weird rendering glitches. The solution is SwingUtilities.invokeLater(), which schedules a piece of code to run on the EDT as soon as it's free.

connectBtn.addActionListener(e -> {
    // Start a new thread so we don't block the EDT
    new Thread(() -> {
        try {
            Thread.sleep(2000); 
            // Now, jump back onto the EDT to update the UI
            SwingUtilities.invokeLater(() -> {
                statusLabel.setText("Status: Connected!");
            });
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }).start();
});

Now the button clicks, the UI remains responsive (you can even drag the window around), and the label updates once the background work is finished. This pattern—Worker Thread $\rightarrow$ invokeLater $\rightarrow$ UI Update—is the heartbeat of every legacy Swing application you'll ever maintain.




📋 Practical Task

Build a Legacy Server Resource Monitor

Your goal is to create a small Swing application that mimics a server monitoring tool. The application must meet the following requirements:

  • The Layout: Use a JFrame containing a JPanel. The panel should use a FlowLayout to hold a JLabel (showing "CPU Usage: 0%") and a JButton (labeled "Refresh Stats").
  • The Logic: When the "Refresh Stats" button is clicked, the application must simulate a data fetch.
    • The "fetch" should happen on a background thread and last for 1.5 seconds.
    • While the fetch is happening, the button should be disabled (setEnabled(false)) so the user can't spam it.
    • After the 1.5 seconds, the JLabel should be updated to display a random CPU percentage (e.g., "CPU Usage: 42%") and the button should be re-enabled.
  • The Constraint: All updates to the label and button must be wrapped in SwingUtilities.invokeLater() to ensure thread safety on the Event Dispatch Thread.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.