1. Swing Components
Swing is a Java library for creating platform-independent GUIs, part of the Java Foundation Classes (JFC) in the javax.swing
package. Swing components are lightweight (drawn by Java, not native OS) and highly customizable.
-
Key Characteristics:
- Built on top of AWT (Abstract Window Toolkit) but more flexible and feature-rich.
- Components are in
javax.swing
(e.g.,JFrame
,JButton
,JLabel
). - Platform-independent, with customizable look and feel.
- Supports MVC (Model-View-Controller) architecture for separating data and UI.
-
Common Swing Components:
- Containers:
JFrame
: Top-level window with a title bar and borders.JPanel
: General-purpose container for grouping components.JDialog
: Pop-up dialog for user interaction.
- Basic Controls:
JButton
: Clickable button.JLabel
: Displays text or images.JTextField
: Single-line text input.JTextArea
: Multi-line text input.JCheckBox
,JRadioButton
: Selection options.JComboBox
: Dropdown list.
- Complex Components:
JTable
: Displays tabular data.JTree
: Displays hierarchical data.JList
: Displays a list of items.
- Menus:
JMenuBar
,JMenu
,JMenuItem
: For menu systems.
- Containers:
-
Example:
package com.example.myapp; import javax.swing.*; public class SwingDemo { public static void main(String[] args) { JFrame frame = new JFrame("Swing Demo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 200); // Add components JLabel label = new JLabel("Hello, Swing!"); JButton button = new JButton("Click Me"); JTextField textField = new JTextField(10); JPanel panel = new JPanel(); panel.add(label); panel.add(textField); panel.add(button); frame.add(panel); frame.setVisible(true); } }
-
Key Points:
- Always set
JFrame.setDefaultCloseOperation()
(e.g.,EXIT_ON_CLOSE
). - Use
setVisible(true)
to display the frame. - Components must be added to a container (e.g.,
JPanel
orJFrame
’s content pane). - Swing components throw unchecked exceptions (e.g.,
NullPointerException
) if misconfigured.
- Always set
2. Laying Out Components in a Container
Layout managers control the positioning and sizing of components within a container (e.g., JPanel
, JFrame
). Swing provides several layout managers to organize components flexibly.
-
Common Layout Managers:
FlowLayout
:- Arranges components in a row, wrapping to the next line if needed.
- Default for
JPanel
. - Example:
panel.setLayout(new FlowLayout()); panel.add(new JButton("Button 1")); panel.add(new JButton("Button 2"));
BorderLayout
:- Divides the container into five regions:
NORTH
,SOUTH
,EAST
,WEST
,CENTER
. - Default for
JFrame
’s content pane. - Example:
frame.setLayout(new BorderLayout()); frame.add(new JButton("North"), BorderLayout.NORTH); frame.add(new JButton("Center"), BorderLayout.CENTER);
- Divides the container into five regions:
GridLayout
:- Arranges components in a grid (equal-sized cells).
- Example:
panel.setLayout(new GridLayout(2, 2)); panel.add(new JButton("1")); panel.add(new JButton("2")); panel.add(new JButton("3")); panel.add(new JButton("4"));
BoxLayout
:- Arranges components in a single row or column.
- Example:
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); panel.add(new JButton("Top")); panel.add(new JButton("Bottom"));
GridBagLayout
:- Highly flexible, grid-based layout with customizable constraints.
- Example:
panel.setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; panel.add(new JButton("Button"), gbc);
-
Example (Combining Layouts):
package com.example.myapp; import javax.swing.*; import java.awt.*; public class LayoutDemo { public static void main(String[] args) { JFrame frame = new JFrame("Layout Demo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(400, 300); // BorderLayout for frame frame.setLayout(new BorderLayout()); // Panel with FlowLayout JPanel topPanel = new JPanel(new FlowLayout()); topPanel.add(new JLabel("Top")); topPanel.add(new JTextField(10)); frame.add(topPanel, BorderLayout.NORTH); // Panel with GridLayout JPanel centerPanel = new JPanel(new GridLayout(2, 2)); centerPanel.add(new JButton("1")); centerPanel.add(new JButton("2")); centerPanel.add(new JButton("3")); centerPanel.add(new JButton("4")); frame.add(centerPanel, BorderLayout.CENTER); frame.setVisible(true); } }
-
Key Points:
- Set the layout manager using
setLayout()
. - Use
null
layout for absolute positioning (not recommended, as it’s not responsive). - Combine layouts by nesting panels with different layout managers.
- Layout managers handle resizing and alignment automatically.
- Set the layout manager using
3. Panels
Panels (JPanel
) are lightweight containers used to group and organize components within a larger container (e.g., JFrame
). They are versatile and support any layout manager.
-
Key Characteristics:
- Default layout:
FlowLayout
. - Can contain other components (e.g., buttons, labels) or nested panels.
- Used to modularize UI design (e.g., separate sections of a form).
- Default layout:
-
Example:
package com.example.myapp; import javax.swing.*; import java.awt.*; public class PanelDemo { public static void main(String[] args) { JFrame frame = new JFrame("Panel Demo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 200); // Main panel with BorderLayout JPanel mainPanel = new JPanel(new BorderLayout()); // Sub-panel 1 (FlowLayout) JPanel topPanel = new JPanel(new FlowLayout()); topPanel.add(new JLabel("Name:")); topPanel.add(new JTextField(10)); mainPanel.add(topPanel, BorderLayout.NORTH); // Sub-panel 2 (GridLayout) JPanel buttonPanel = new JPanel(new GridLayout(1, 2)); buttonPanel.add(new JButton("OK")); buttonPanel.add(new JButton("Cancel")); mainPanel.add(buttonPanel, BorderLayout.SOUTH); frame.add(mainPanel); frame.setVisible(true); } }
-
Key Points:
- Use panels to break down complex UIs into manageable sections.
- Each panel can have its own layout manager.
- Add panels to
JFrame
’s content pane (frame.add(panel)
). - Panels are transparent by default; set background with
setBackground(Color)
.
4. Look & Feel
Look and Feel (L&F) defines the visual appearance and behavior of Swing components (e.g., colors, fonts, borders). Swing supports pluggable look and feel, allowing you to change the UI style.
-
Default Look and Feel:
- Cross-platform (Java’s “Metal” look, or “Nimbus” in newer versions).
- Platform-specific (e.g., Windows, macOS) via
UIManager.setLookAndFeel()
.
-
Changing Look and Feel:
- Use
UIManager.setLookAndFeel(String className)
or predefined look and feel classes. - Common options:
com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel
(modern, cross-platform).UIManager.getSystemLookAndFeelClassName()
(native OS look).
- Example:
package com.example.myapp; import javax.swing.*; import java.awt.*; public class LookAndFeelDemo { public static void main(String[] args) { try { // Set Nimbus Look and Feel UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); } catch (Exception e) { System.err.println("Error setting look and feel: " + e.getMessage()); } JFrame frame = new JFrame("Look and Feel Demo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 200); JPanel panel = new JPanel(); panel.add(new JButton("Click Me")); panel.add(new JLabel("Nimbus Look")); frame.add(panel); frame.setVisible(true); } }
- Use
-
Key Points:
- Set look and feel before creating components for consistency.
- Handle exceptions (
UnsupportedLookAndFeelException
, etc.). - Use
UIManager.getInstalledLookAndFeels()
to list available L&Fs. - Nimbus is recommended for modern applications.
5. Event Listeners
Event listeners handle user interactions (e.g., button clicks, key presses, mouse movements) in Swing. Swing uses the event-driven programming model, where events trigger listener methods.
-
Key Concepts:
- Event: An object (e.g.,
ActionEvent
,MouseEvent
) representing a user action. - Listener: An interface (e.g.,
ActionListener
,MouseListener
) defining methods to handle events. - Source: The component generating the event (e.g.,
JButton
). - Register listeners using
addXXXListener()
methods (e.g.,addActionListener()
).
- Event: An object (e.g.,
-
Common Listeners:
ActionListener
: Handles actions (e.g., button clicks, menu selections).- Method:
actionPerformed(ActionEvent e)
.
- Method:
MouseListener
: Handles mouse events (e.g., clicks, enters/exits).- Methods:
mouseClicked()
,mousePressed()
, etc.
- Methods:
KeyListener
: Handles keyboard events.- Methods:
keyPressed()
,keyReleased()
,keyTyped()
.
- Methods:
WindowListener
: Handles window events (e.g., closing, opening).- Methods:
windowClosing()
,windowOpened()
, etc.
- Methods:
-
Example (ActionListener):
package com.example.myapp; import javax.swing.*; import java.awt.event.*; public class EventListenerDemo { public static void main(String[] args) { JFrame frame = new JFrame("Event Demo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 200); JPanel panel = new JPanel(); JButton button = new JButton("Click Me"); JTextField textField = new JTextField(10); // Add ActionListener button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { textField.setText("Button Clicked!"); } }); panel.add(button); panel.add(textField); frame.add(panel); frame.setVisible(true); } }
-
Lambda Expression (Java 8+):
button.addActionListener(e -> textField.setText("Button Clicked!"));
-
Key Points:
- Listeners are interfaces; implement them using classes, anonymous classes, or lambdas.
- Multiple listeners can be added to a component.
- Use
getSource()
orgetActionCommand()
inActionEvent
to identify the source. - Handle exceptions (e.g.,
IllegalArgumentException
) for invalid listener configurations.
6. Concurrency in Swing
Swing is not thread-safe, meaning most Swing components must be accessed from the Event Dispatch Thread (EDT), a single thread responsible for handling GUI events and updates. Concurrency in Swing ensures responsive UIs during long-running tasks.
-
Key Concepts:
- Event Dispatch Thread (EDT):
- Handles all GUI events (e.g., button clicks, repaints).
- All Swing component creation and updates must occur on the EDT.
- SwingUtilities.invokeLater():
- Schedules code to run on the EDT.
- Example:
SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("Demo"); frame.setVisible(true); });
- SwingUtilities.invokeAndWait():
- Runs code on the EDT and waits for completion (used rarely).
- Worker Threads:
- Perform long-running tasks (e.g., file I/O, network calls) off the EDT to avoid freezing the UI.
- Use
SwingWorker
for background tasks with UI updates.
- Event Dispatch Thread (EDT):
-
SwingWorker:
- A utility class (
javax.swing.SwingWorker
) for running tasks in a background thread and updating the UI on the EDT. - Methods:
doInBackground()
: Runs the task in a worker thread.done()
: Executes on the EDT after the task completes.publish()/process()
: Sends intermediate results to the EDT.
- A utility class (
-
Example (SwingWorker):
package com.example.myapp; import javax.swing.*; import java.awt.*; import java.util.List; public class ConcurrencyDemo { public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("Concurrency Demo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 200); JLabel label = new JLabel("Waiting..."); JButton button = new JButton("Start Task"); JPanel panel = new JPanel(); panel.add(button); panel.add(label); frame.add(panel); // ActionListener with SwingWorker button.addActionListener(e -> { SwingWorker<String, String> worker = new SwingWorker<>() { @Override protected String doInBackground() throws Exception { // Simulate long-running task for (int i = 1; i <= 5; i++) { Thread.sleep(1000); publish("Processing " + i + "..."); } return "Task Completed!"; } @Override protected void process(List<String> chunks) { // Update UI on EDT label.setText(chunks.get(chunks.size() - 1)); } @Override protected void done() { try { label.setText(get()); // Final result } catch (Exception ex) { label.setText("Error: " + ex.getMessage()); } } }; worker.execute(); }); frame.setVisible(true); }); } }
-
Key Points:
- Always create and modify Swing components on the EDT (
invokeLater()
). - Use
SwingWorker
for background tasks to keep the UI responsive. - Avoid long-running tasks on the EDT to prevent freezing.
- Handle exceptions (e.g.,
InterruptedException
,ExecutionException
) inSwingWorker
.
- Always create and modify Swing components on the EDT (
Connecting to Previous Topics
-
Packages:
- Swing classes are in
javax.swing
andjava.awt
. - Custom Swing applications should be organized in packages (e.g.,
com.example.myapp.gui
). - Ensure
CLASSPATH
includes Swing libraries (standard in Java).
- Swing classes are in
-
Interfaces:
- Event listeners (e.g.,
ActionListener
,MouseListener
) are interfaces. - Example:
public class MyListener implements ActionListener
. - Swing components implement interfaces like
Serializable
andAccessible
.
- Event listeners (e.g.,
-
Exception Handling:
- Swing operations may throw unchecked exceptions (e.g.,
NullPointerException
,IllegalArgumentException
). SwingWorker
tasks may throwInterruptedException
orExecutionException
.- Example:
try { Thread.sleep(1000); // In SwingWorker } catch (InterruptedException e) { System.err.println("Task interrupted"); }
- Swing operations may throw unchecked exceptions (e.g.,
-
Multithreading:
- Swing relies on the EDT, a single-threaded model.
- Use
SwingWorker
orinvokeLater()
for thread-safe GUI updates. volatile
or synchronized methods may be used in Swing applications for shared data.
-
I/O:
- Swing applications often read/write files (e.g., saving user preferences).
- Example: Use
JFileChooser
for file selection.JFileChooser chooser = new JFileChooser(); if (chooser.showOpenDialog(frame) == JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); // Read file }
-
Strings and Characters:
- Swing components use
String
for text (e.g.,JLabel.setText("Hello")
). - Use
StringBuilder
for dynamic text updates inSwingWorker
. - Example:
StringBuilder sb = new StringBuilder(); sb.append("Result: ").append(count); label.setText(sb.toString());
- Swing components use
Practice Program:
package com.example.myapp;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SwingApp {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Swing App");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
// Panel with BorderLayout
JPanel panel = new JPanel(new BorderLayout());
// Top: Input
JPanel topPanel = new JPanel(new FlowLayout());
JTextField textField = new JTextField(10);
topPanel.add(new JLabel("Enter text:"));
topPanel.add(textField);
panel.add(topPanel, BorderLayout.NORTH);
// Center: Output
JLabel outputLabel = new JLabel("Output: ");
panel.add(outputLabel, BorderLayout.CENTER);
// Bottom: Button
JButton button = new JButton("Submit");
button.addActionListener(e -> {
SwingWorker<Void, String> worker = new SwingWorker<>() {
@Override
protected Void doInBackground() throws Exception {
publish("Processing: " + textField.getText());
Thread.sleep(1000);
return null;
}
@Override
protected void process(java.util.List<String> chunks) {
outputLabel.setText(chunks.get(chunks.size() - 1));
}
};
worker.execute();
});
panel.add(button, BorderLayout.SOUTH);
frame.add(panel);
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception ex) {
System.err.println("Look and feel error: " + ex.getMessage());
}
frame.setVisible(true);
});
}
}
Compile and Run:
javac com/example/myapp/SwingApp.java
java -cp . com.example.myapp.SwingApp