By John Doe
Posted on May 17, 2024
This guide is for Java developers who already know their way around JFrame, JPanel, and BorderLayout—and want to build professional-grade desktop applications with Swing. We cover advanced layout managers, custom Graphics2D rendering, safe multithreading with SwingWorker, and practical integration patterns. Each major section includes annotated, runnable code examples. A complete GitHub repository with all samples is available here.
A Quick Refresher: What You're Expected to Know
Swing is Java's mature GUI toolkit, built on top of AWT with a lightweight component architecture. Before proceeding, you should already understand:
- Core containers:
JFrame,JPanel,JDialog - Basic components:
JButton,JTextField,JTable,JTree - Fundamental layout managers:
BorderLayout,FlowLayout,GridLayout - The event model: listeners, adapters, and action commands
If any of these are unfamiliar, pause here and revisit an introductory Swing tutorial. The sections below assume you're ready to move beyond boilerplate into advanced implementation.
Advanced Layout Management
Swing's layout system separates component sizing and positioning from the components themselves. While BorderLayout and GridBagLayout handle many cases, complex forms and responsive UIs demand more precision.
GroupLayout
GroupLayout, originally developed for the NetBeans GUI builder, excels at creating alignment-rich forms without nested panels. It works by defining horizontal and vertical groups independently.
Here's a minimal, compilable example that aligns a label, text field, and button:
import javax.swing.*;
import java.awt.*;
public class GroupLayoutExample {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GroupLayout Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
JLabel label = new JLabel("Username:");
JTextField textField = new JTextField(20);
JButton button = new JButton("Submit");
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
// Horizontal group
layout.setHorizontalGroup(
layout.createSequentialGroup()
.addComponent(label)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(textField, GroupLayout.DEFAULT_SIZE, 200, Short.MAX_VALUE)
.addComponent(button)
);
// Vertical group
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(label)
.addComponent(textField)
.addComponent(button)
);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Key points:
setAutoCreateGaps(true)automatically inserts spacing between components.- Horizontal and vertical groups are defined separately, which can be disorienting at first but enables precise alignment control.
GroupLayout.PREFERRED_SIZEandGroupLayout.DEFAULT_SIZElet components negotiate their natural sizes.
Custom Layout Managers
When GroupLayout, MigLayout, or GridBagLayout still constrain your design, implement LayoutManager2 directly. Override these five methods:
public class CircleLayout implements LayoutManager {
@Override
public void addLayoutComponent(String name, Component comp) {}
@Override
public void removeLayoutComponent(Component comp) {}
@Override
public Dimension preferredLayoutSize(Container parent) {
return new Dimension(400, 400);
}
@Override
public Dimension minimumLayoutSize(Container parent) {
return new Dimension(200, 200);
}
@Override
public void layoutContainer(Container parent) {
int n = parent.getComponentCount();
double radius = Math.min(parent.getWidth(), parent.getHeight()) / 2.5;
double centerX = parent.getWidth() / 2.0;
double centerY = parent.getHeight() / 2.0;
for (int i = 0; i < n; i++) {
Component c = parent.getComponent(i);
double angle = 2 * Math.PI * i / n;
int x = (int) (centerX + radius * Math.cos(angle)) - c.getWidth() / 2;
int y = (int) (centerY + radius * Math.sin(angle)) - c.getHeight() / 2;
c.setBounds(x, y, c.getPreferredSize().width, c.getPreferredSize().height);
} 














