Java Swing编程:从基础到组件应用
1. Swing应用中的事件处理
在Swing应用里,为按钮添加事件处理是常见操作。以下代码展示了如何为两个按钮“Alpha”和“Beta”添加事件处理:
jbtnAlpha.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
jlab.setText("Alpha was pressed.");
}
});
jbtnBeta.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
jlab.setText("Beta was pressed.");
}
});
从JDK 8开始,也可以使用lambda表达式来实现事件处理,例如为“Alpha”按钮添加事件处理可以写成:
jbtnAlpha.addActionListener( (ae) -> jlab.setText("Alpha was pressed."));
lambda表达式的代码更简洁。后续示例为兼容JDK 8之前的版本,未使用lambda表达式,但在编写新代码时可以考虑使用。
添加事件处理后,将按钮添加到
JFrame
的内容面板:
jfrm.add(jbtnAlpha);
jfrm.add(jbtnBeta);
最后,将标签添加到内容面板并使窗口可见。运行程序后,每次按下按钮,标签会显示相应的消息。
需要注意的是,所有事件处理方法(如
actionPerformed()
)都在事件调度线程上调用,因此事件处理方法必须快速返回,避免减慢应用程序。若应用程序在事件发生后需要执行耗时操作,必须使用单独的线程。
2. 创建Swing小程序
Swing小程序是另一种常见的Swing程序类型。与基于AWT的小程序不同,Swing小程序继承自
JApplet
而非
Applet
。
JApplet
继承自
Applet
,包含了
Applet
的所有功能,并增加了对Swing的支持。
Swing小程序使用与之前章节描述相同的四个生命周期方法:
init()
、
start()
、
stop()
和
destroy()
,只需重写小程序需要的方法即可。Swing中的绘图方式与AWT不同,Swing小程序通常不会重写
paint()
方法。
以下是一个简单的Swing小程序示例:
// A simple Swing-based applet
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/*
This HTML can be used to launch the applet:
<applet code="MySwingApplet" width=220 height=90>
</applet>
*/
public class MySwingApplet extends JApplet {
JButton jbtnAlpha;
JButton jbtnBeta;
JLabel jlab;
// Initialize the applet.
public void init() {
try {
SwingUtilities.invokeAndWait(new Runnable () {
public void run() {
makeGUI(); // initialize the GUI
}
});
} catch(Exception exc) {
System.out.println("Can’t create because of "+ exc);
}
}
// Set up and initialize the GUI.
private void makeGUI() {
// Set the applet to use flow layout.
setLayout(new FlowLayout());
// Make two buttons.
jbtnAlpha = new JButton("Alpha");
jbtnBeta = new JButton("Beta");
// Add action listener for Alpha.
jbtnAlpha.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent le) {
jlab.setText("Alpha was pressed.");
}
});
// Add action listener for Beta.
jbtnBeta.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent le) {
jlab.setText("Beta was pressed.");
}
});
// Add the buttons to the content pane.
add(jbtnAlpha);
add(jbtnBeta);
// Create a text-based label.
jlab = new JLabel("Press a button.");
// Add the label to the content pane.
add(jlab);
}
}
这个小程序有两个要点:一是
MySwingApplet
继承自
JApplet
;二是
init()
方法通过
invokeAndWait()
在事件调度线程上初始化Swing组件,确保在初始化完成后才返回,保证GUI完全构建好后才调用
start()
方法。
3. Swing中的绘图
Swing组件功能强大,还允许直接在框架、面板或其他组件(如
JLabel
)的显示区域进行绘图。虽然很多Swing应用可能不会直接在组件表面绘图,但对于有此需求的应用是可行的。
3.1 绘图基础
Swing的绘图机制基于原始的AWT机制,但提供了更精细的控制。在AWT中,
Component
类定义了
paint()
方法用于直接在组件表面绘制输出,该方法通常由运行时系统调用,而非程序主动调用。
Swing的轻量级组件继承了
paint()
方法,但不会直接重写它来绘图。Swing采用更复杂的绘图方法,包含三个不同的方法:
paintComponent()
、
paintBorder()
和
paintChildren()
。要在Swing组件表面绘图,需创建组件的子类并重写
paintComponent()
方法,该方法用于绘制组件内部。重写
paintComponent()
时,首先要调用
super.paintComponent()
,确保组件正确绘制。
protected void paintComponent(Graphics g)
参数
g
是用于输出的图形上下文。
要在程序控制下使组件绘图,可调用
repaint()
方法,它在Swing中的工作方式与在AWT中相同。调用
repaint()
会使系统尽快调用
paint()
方法,在Swing中调用
paint()
会导致调用
paintComponent()
。
3.2 计算可绘制区域
在组件表面绘图时,要确保输出限制在边框内。虽然Swing会自动裁剪超出组件边界的输出,但仍可能绘制到边框上。为避免这种情况,需要计算组件的可绘制区域,即组件当前大小减去边框占用的空间。
可通过
getInsets()
方法获取边框宽度:
Insets getInsets()
该方法返回一个
Insets
对象,包含边框的尺寸信息,可通过以下字段获取具体值:
int top;
int bottom;
int left;
int right;
结合组件的宽度和高度(通过
getWidth()
和
getHeight()
方法获取),可计算出可用的绘图区域。
3.3 绘图示例
以下程序创建了一个
PaintPanel
类,继承自
JPanel
,用于在面板上随机绘制线条:
// Paint lines to a panel.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
class PaintPanel extends JPanel {
Insets ins; // holds the panel’s insets
Random rand; // used to generate random numbers
// Construct a panel.
PaintPanel() {
// Put a border around the panel.
setBorder(
BorderFactory.createLineBorder(Color.RED, 5));
rand = new Random();
}
// Override the paintComponent() method.
protected void paintComponent(Graphics g) {
// Always call the superclass method first.
super.paintComponent(g);
int x, y, x2, y2;
// Get the height and width of the component.
int height = getHeight();
int width = getWidth();
// Get the insets.
ins = getInsets();
// Draw ten lines whose endpoints are randomly generated.
for(int i=0; i < 10; i++) {
// Obtain random coordinates that define
// the endpoints of each line.
x = rand.nextInt(width-ins.left);
y = rand.nextInt(height-ins.bottom);
x2 = rand.nextInt(width-ins.left);
y2 = rand.nextInt(height-ins.bottom);
// Draw the line.
g.drawLine(x, y, x2, y2);
}
}
}
class PaintDemo {
JLabel jlab;
PaintPanel pp;
PaintDemo() {
// Create a new JFrame container.
JFrame jfrm = new JFrame("Paint Demo");
// Give the frame an initial size.
jfrm.setSize(200, 150);
// Terminate the program when the user closes the application.
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create the panel that will be painted.
pp = new PaintPanel();
// Add the panel to the content pane. Because the default
// border layout is used, the panel will automatically be
// sized to fit the center region.
jfrm.add(pp);
// Display the frame.
jfrm.setVisible(true);
}
public static void main(String args[]) {
// Create the frame on the event dispatching thread.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new PaintDemo();
}
});
}
}
PaintPanel
类重写了
paintComponent()
方法,确保线条绘制在可绘制区域内。运行程序后,每次调整窗口大小或隐藏并恢复窗口,都会绘制一组新的线条。
4. 探索Swing组件
Swing提供了丰富的组件,如按钮、复选框、树和表格等,这些组件功能强大且可高度定制。以下是本章介绍的Swing组件类:
| 组件类 | 说明 |
| ---- | ---- |
| JButton | 按钮 |
| JCheckBox | 复选框 |
| JComboBox | 下拉框 |
| JLabel | 标签 |
| JList | 列表 |
| JRadioButton | 单选按钮 |
| JScrollPane | 滚动面板 |
| JTabbedPane | 选项卡面板 |
| JTable | 表格 |
| JTextField | 文本框 |
| JToggleButton | 切换按钮 |
| JTree | 树 |
这些组件都是轻量级的,继承自
JComponent
。此外,还介绍了
ButtonGroup
类用于封装互斥的Swing按钮,以及
ImageIcon
类用于封装图形图像。
5. JLabel和ImageIcon
JLabel
是Swing中最易用的组件,可用于显示文本和/或图标,它是被动组件,不响应用户输入。
JLabel
定义了多个构造函数,例如:
JLabel(Icon icon)
JLabel(String str)
JLabel(String str, Icon icon, int align)
参数
str
和
icon
分别是标签的文本和图标,
align
参数指定文本和/或图标在标签内的水平对齐方式,必须是
LEFT
、
RIGHT
、
CENTER
、
LEADING
或
TRAILING
之一。
图标由
Icon
接口指定,可通过
ImageIcon
类获取图标,例如:
ImageIcon(String filename)
该构造函数从指定文件中获取图像。
可通过以下方法获取和设置标签的图标和文本:
Icon getIcon()
String getText()
void setIcon(Icon icon)
void setText(String str)
以下小程序示例展示了如何创建和显示包含图标和字符串的标签:
// Demonstrate JLabel and ImageIcon.
import java.awt.*;
import javax.swing.*;
/*
<applet code="JLabelDemo" width=250 height=200>
</applet>
*/
public class JLabelDemo extends JApplet {
public void init() {
try {
SwingUtilities.invokeAndWait(
new Runnable() {
public void run() {
makeGUI();
}
}
);
} catch (Exception exc) {
System.out.println("Can't create because of " + exc);
}
}
private void makeGUI() {
ImageIcon icon = new ImageIcon("hourglass.png");
JLabel jlab = new JLabel("Hourglass", icon, SwingConstants.CENTER);
add(jlab);
}
}
该程序创建了一个
ImageIcon
对象,用于表示
hourglass.png
文件中的图像,并将其作为参数传递给
JLabel
构造函数。最后将标签添加到内容面板。
Java Swing编程:从基础到组件应用
6. JButton 按钮组件
JButton 是 Swing 中常用的组件,用于触发操作。以下是创建和使用 JButton 的示例:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class JButtonExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JButton Example");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JButton button = new JButton("Click Me");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frame, "Button Clicked!");
}
});
frame.add(button);
frame.setVisible(true);
}
}
在这个示例中,创建了一个 JButton 并添加了一个动作监听器。当按钮被点击时,会弹出一个消息对话框。
7. JCheckBox 复选框组件
JCheckBox 用于提供多个选项的选择,用户可以选择一个或多个选项。以下是使用 JCheckBox 的示例:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
public class JCheckBoxExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JCheckBox Example");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JCheckBox checkBox1 = new JCheckBox("Option 1");
JCheckBox checkBox2 = new JCheckBox("Option 2");
checkBox1.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
System.out.println("Option 1 selected");
} else {
System.out.println("Option 1 deselected");
}
}
});
checkBox2.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
System.out.println("Option 2 selected");
} else {
System.out.println("Option 2 deselected");
}
}
});
frame.add(checkBox1);
frame.add(checkBox2);
frame.setVisible(true);
}
}
在这个示例中,创建了两个 JCheckBox 并为它们添加了项监听器。当复选框的状态改变时,会输出相应的信息。
8. JComboBox 下拉框组件
JComboBox 提供了一个下拉列表,用户可以从中选择一个选项。以下是使用 JComboBox 的示例:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class JComboBoxExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JComboBox Example");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
String[] options = {"Option 1", "Option 2", "Option 3"};
JComboBox<String> comboBox = new JComboBox<>(options);
comboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String selectedOption = (String) comboBox.getSelectedItem();
System.out.println("Selected: " + selectedOption);
}
});
frame.add(comboBox);
frame.setVisible(true);
}
}
在这个示例中,创建了一个 JComboBox 并为其添加了一个动作监听器。当用户选择一个选项时,会输出所选的选项。
9. JList 列表组件
JList 用于显示一个列表,用户可以从中选择一个或多个项目。以下是使用 JList 的示例:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ListSelectionEvent;
import java.awt.event.ListSelectionListener;
public class JListExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JList Example");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
String[] items = {"Item 1", "Item 2", "Item 3", "Item 4"};
JList<String> list = new JList<>(items);
list.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
String selectedItem = list.getSelectedValue();
System.out.println("Selected: " + selectedItem);
}
}
});
JScrollPane scrollPane = new JScrollPane(list);
frame.add(scrollPane);
frame.setVisible(true);
}
}
在这个示例中,创建了一个 JList 并为其添加了一个列表选择监听器。当用户选择一个项目时,会输出所选的项目。
10. JRadioButton 单选按钮组件
JRadioButton 用于提供一组互斥的选项,用户只能选择其中一个选项。通常会使用 ButtonGroup 来管理一组 JRadioButton。以下是使用 JRadioButton 的示例:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class JRadioButtonExample {
public static void main(String[] args) {
JFrame frame = new JFrame("JRadioButton Example");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JRadioButton radioButton1 = new JRadioButton("Option 1");
JRadioButton radioButton2 = new JRadioButton("Option 2");
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(radioButton1);
buttonGroup.add(radioButton2);
radioButton1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Option 1 selected");
}
});
radioButton2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Option 2 selected");
}
});
frame.add(radioButton1);
frame.add(radioButton2);
frame.setVisible(true);
}
}
在这个示例中,创建了两个 JRadioButton 并将它们添加到一个 ButtonGroup 中。当用户选择一个单选按钮时,会输出相应的信息。
11. Swing 组件使用流程总结
以下是使用 Swing 组件的一般流程:
1. 创建 JFrame 或 JApplet 作为容器。
2. 设置容器的大小、布局和关闭操作。
3. 创建所需的 Swing 组件,如 JButton、JCheckBox 等。
4. 为组件添加监听器(如果需要),以处理用户的交互。
5. 将组件添加到容器中。
6. 使容器可见。
graph TD;
A[创建容器] --> B[设置容器属性];
B --> C[创建组件];
C --> D[添加监听器];
D --> E[添加组件到容器];
E --> F[使容器可见];
通过以上步骤,可以创建出功能丰富的 Swing 应用程序。不同的组件有不同的特点和用途,根据实际需求选择合适的组件进行组合使用。
超级会员免费看
1704

被折叠的 条评论
为什么被折叠?



