Swing applications are built using a hierarchy of containers and components. The top-level window is typically represented by JFrame, while intermediate containers like JPanel are used to group components. Atomic controls such as JButton and JLabel are placed within these containers.
Below is an example of setting up a basic window structure:
// Initialize the main application window
JFrame mainWindow = new JFrame("Application Title");
JPanel contentPanel = new JPanel();
mainWindow.setContentPane(contentPanel);
// Add a button component
JButton actionButton = new JButton("Execute");
contentPanel.add(actionButton);
// Add a label for static text
JLabel statusLabel = new JLabel("Ready");
contentPanel.add(statusLabel);
// Attach an action listener using a lambda expression
actionButton.addActionListener(e -> System.out.println("Action triggered"));
// Attach a listener using an anonymous inner class
actionButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Command: " + e.getActionCommand());
}
});
Extending JFrame
To promote code reuse and encapsulation, it is common practice to create a subclass of JFrame. This allows specific window configurations to be defined within the class constructor.
public class ApplicationWindow extends JFrame {
public ApplicationWindow(String title, JPanel rootPanel) {
super(title);
// Ensure the application exits when the window is closed
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setContentPane(rootPanel);
this.setSize(800, 500);
}
}
// Usage
JPanel mainPanel = new JPanel();
ApplicationWindow window = new ApplicationWindow("Demo", mainPanel);
window.setVisible(true);
Text Inputs and Selection Controls
Swing provides various controls for data entry and selection:
- JTextField: A single-line text input field.
- JCheckBox: A binary selection component (selected/unselected).
- JComboBox: A drop-down list that allows the user to select one item from a list.
// Checkbox usage
JCheckBox agreeBox = new JCheckBox("I agree to terms");
agreeBox.setSelected(true); // Set initial state
if (agreeBox.isSelected()) { /* Logic here */ }
// Generic JComboBox usage
JComboBox<String> colorSelector = new JComboBox<>();
colorSelector.addItem("Red");
colorSelector.addItem("Blue");
colorSelector.addItem("Green");
String selected = (String) colorSelector.getSelectedItem();
Layout Management
Layout managers determine the position and size of components within a container. By default, JPanel uses FlowLayout, which arranges components left-to-right.
BorderLayout
BorderLayout divides the container into five regions: NORTH, SOUTH, EAST, WEST, and CENTER.
contentPanel.setLayout(new BorderLayout());
contentPanel.add(new JLabel("North"), BorderLayout.NORTH);
contentPanel.add(new JLabel("South"), BorderLayout.SOUTH);
Custom Layout Managers
For complex interfaces, you can implement LayoutManager2. The layoutContainer method is responsible for calculating the bounds (x, y, width, height) for every child component.
public class SimpleGridLayout implements LayoutManager2 {
@Override
public void layoutContainer(Container parent) {
int w = parent.getWidth();
int h = parent.getHeight();
// Example logic: grid layout calculation
for (Component comp : parent.getComponents()) {
comp.setBounds(0, 0, w, h);
}
}
// Other interface implementations...
}
Color Models
Colors in Swing are represented by the Color class, typically using the RGB model.
// Solid RGB color
Color redColor = new Color(255, 0, 0);
// RGBA color with transparency (Alpha 0-255)
Color translucentBlue = new Color(0, 0, 255, 128);
Custom Rendering
To create custom visual components, extend JPanel and override the paintComponent method. This method provides a Graphics object (the "canvas") for drawing shapes and text.
public class CustomPanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // Crucial for clearing background
int w = getWidth();
int h = getHeight();
// Draw a background rectangle
g.setColor(Color.YELLOW);
g.fillRect(0, 0, w, h);
// Draw an arc (pie slice)
g.setColor(Color.CYAN);
g.fillArc(50, 50, 100, 100, 0, 90);
}
}
Geometric Primitives
The Graphics class supports various drawing operations:
fillRect(x, y, w, h): Draws a filled rectangle.drawOval(x, y, w, h): Draws the outline of an ellipse.fillArc(x, y, w, h, startAngle, arcAngle): Draws a filled sector.drawLine(x1, y1, x2, y2): Draws a straight line.
Image Handling
Images are loaded using javax.imageio.ImageIO. To display an image while maintaining its aspect ratio, calculations are required to fit the image within the component bounds.
public class ImageView extends JPanel {
private BufferedImage sourceImage;
public void setImage(File imgFile) throws IOException {
sourceImage = ImageIO.read(imgFile);
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (sourceImage != null) {
int panelW = getWidth();
int panelH = getHeight();
int imgW = sourceImage.getWidth();
int imgH = sourceImage.getHeight();
// Calculate aspect ratio
double scale = Math.min((double) panelW / imgW, (double) panelH / imgH);
int drawW = (int) (imgW * scale);
int drawH = (int) (imgH * scale);
// Center the image
int x = (panelW - drawW) / 2;
int y = (panelH - drawH) / 2;
g.drawImage(sourceImage, x, y, drawW, drawH, null);
}
}
}
Mouse Event Handling
Interactions are handled via listeners. MouseAdapter is a convenience class that implements all listener interfaces with empty methods, allowing you to override only the events you need.
public class InteractivePanel extends JPanel {
public InteractivePanel() {
MyMouseListener handler = new MyMouseListener();
addMouseListener(handler);
addMouseMotionListener(handler);
}
private class MyMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
System.out.println("Pressed at: " + e.getPoint());
}
@Override
public void mouseDragged(MouseEvent e) {
System.out.println("Dragging to: " + e.getPoint());
}
}
}
Freheand Drawing Example
To implement a drawing tool, record coordinates in a list during mouseDragged and render lines connecting them in paintComponent.
public class SketchPad extends JPanel {
private List<Point> points = new ArrayList<>();
public SketchPad() {
MouseAdapter dragHandler = new MouseAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
points.add(e.getPoint());
repaint();
}
@Override
public void mousePressed(MouseEvent e) {
points.clear();
points.add(e.getPoint());
}
};
addMouseListener(dragHandler);
addMouseMotionListener(dragHandler);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
for (int i = 1; i < points.size(); i++) {
Point p1 = points.get(i - 1);
Point p2 = points.get(i);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
}
Styling with Borders
Visual separation is achieved using borders. BorderFactory provides static methods to create standard borders.
LineBorder lineBorder = new LineBorder(Color.BLUE, 2);
component.setBorder(lineBorder);
// Compound borders (nesting borders)
Border outer = BorderFactory.createEmptyBorder(5, 5, 5, 5);
Border inner = BorderFactory.createLineBorder(Color.BLACK);
Border combined = BorderFactory.createCompoundBorder(outer, inner);
component.setBorder(combined);
Dialogs and File Selection
JOptionPane offers standard pre-built dialogs for alerts, confirmations, and inputs. For file system interactions, JFileChooser is used.
// Simple message dialog
JOptionPane.showMessageDialog(this, "Operation Complete");
// File Open Dialog
JFileChooser fileChooser = new JFileChooser();
int userSelection = fileChooser.showOpenDialog(this);
if (userSelection == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
System.out.println("Selected: " + selectedFile.getAbsolutePath());
}
Context Menus
JPopupMenu is used for right-click context menus. It is typically triggered on a mouse press event.
JPopupMenu contextMenu = new JPopupMenu();
JMenuItem saveItem = new JMenuItem("Save");
saveItem.addActionListener(e -> performSave());
contextMenu.add(saveItem);
// In the mouse listener
component.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) {
contextMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
});