Java GUI编程进阶:Swing与AWT的100+案例实操
简介:Java Swing和AWT库是用于开发具有丰富交互式用户界面的桌面应用程序。AWT作为基础GUI库,提供与操作系统集成的组件,而Swing在AWT之上,提供跨平台一致性更强的轻量级组件。本课程将通过100多个案例带你深入学习从基础到高级的Java图形用户界面编程技术,涵盖组件、布局、事件处理、对话框、菜单、表格、树、面板、MVC模式、国际化和定制组件等。通过实践这些案例,你将掌握如何使用Swing和AWT构建高效、美观的应用程序。 
1. Java Swing与AWT的介绍
Java Swing 和 AWT(Abstract Window Toolkit)是Java SE的一部分,提供了丰富的GUI组件库,用于构建平台独立的桌面应用程序。 Java AWT 是Java的一个较老的图形用户界面工具包,它依赖于底层操作系统提供的本地组件,因此在不同平台上表现可能会有差异。 Swing 是AWT的一个增强版本,它几乎完全用Java编写,因此提供了更加统一的外观和功能丰富的组件。本章我们将了解Java Swing和AWT的基础概念、它们如何协同工作以及它们各自的特点和优势。
2. 组件的创建与应用
组件是构建用户界面的基本单位,是Java Swing应用程序的核心。在这一章中,我们将探索如何创建和应用各种Swing组件,包括基础组件、复合组件和特殊组件。通过对这些组件的理解和应用,开发者可以构建出功能丰富且用户友好的图形用户界面(GUI)。
2.1 基础组件的使用
基础组件是构建任何GUI应用的基石。在Swing库中,这些组件包括标签、按钮、文本框、列表和组合框等。这些简单的界面元素允许用户进行交互,是所有复杂界面的基础。
2.1.1 标签、按钮和文本框的创建
在Swing中,创建一个基础组件并将其添加到窗口中是一个简单的过程。首先,我们需要创建一个继承自JFrame的主窗口类,在其中初始化组件并设置布局。
import javax.swing.*;
import java.awt.*;
public class BasicComponentsDemo extends JFrame {
private JLabel label;
private JButton button;
private JTextField textField;
public BasicComponentsDemo() {
// 创建标签组件
label = new JLabel("用户名:");
// 创建文本框组件
textField = new JTextField(15);
// 创建按钮组件
button = new JButton("提交");
// 设置窗口布局
setLayout(new FlowLayout());
// 将组件添加到窗口
add(label);
add(textField);
add(button);
// 设置窗口的其他属性
setTitle("基础组件示例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 100);
setVisible(true);
}
public static void main(String[] args) {
// 在事件调度线程中创建和显示GUI
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new BasicComponentsDemo();
}
});
}
}
在上述代码中,我们创建了一个简单的窗口,其中包含了一个标签(用于提示用户输入)、一个文本框(用于用户输入信息)和一个按钮(用于执行操作,如提交数据)。通过设置布局为FlowLayout,Swing会自动处理组件的排列和空间分配。
接下来,让我们进一步探索列表(JList)和组合框(JComboBox)的应用实例。
2.1.2 列表和组合框的应用实例
列表(JList)允许用户从一组预定义的选项中选择一个或多个项目,而组合框(JComboBox)是列表和文本框的组合,它允许用户选择预定义的选项或者输入新的文本。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
public class ListComboBoxDemo extends JFrame {
private JList<String> list;
private JComboBox<String> comboBox;
public ListComboBoxDemo() {
// 初始化列表数据
String[] items = {"苹果", "香蕉", "橙子", "葡萄"};
// 创建列表组件
list = new JList<>(items);
// 创建组合框组件
comboBox = new JComboBox<>(items);
// 设置窗口布局
setLayout(new GridLayout(2, 1));
// 添加组件到窗口
add(new JScrollPane(list));
add(comboBox);
// 设置窗口的其他属性
setTitle("列表和组合框示例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 150);
setVisible(true);
// 添加事件监听器
comboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String selectedItem = (String) comboBox.getSelectedItem();
System.out.println("您选择了: " + selectedItem);
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ListComboBoxDemo();
}
});
}
}
在这个示例中,我们创建了一个JList和一个JComboBox。JList在一个滚动面板中被添加到窗口,它允许用户滚动查看所有的选项。JComboBox被直接添加到了窗口,并且为其添加了一个事件监听器,以响应用户的选择事件。
在列表和组合框的应用实例中,我们展示了如何使用基本组件来创建一个用户交互式的界面。通过上述示例,我们可以了解到Swing库如何为开发者提供丰富的界面组件,并且通过一些简单的代码示例了解了如何使用它们。
2.2 复合组件的构建
复合组件是由基础组件组合而成的界面元素,它们在Swing库中提供了更加复杂的用户交互和更加丰富的界面结构。在这一节中,我们将深入讨论如何构建和应用卡片布局(CardLayout)和选项卡面板(JTabbedPane),以及如何使用分隔面板(JDesktopPane)和滑动面板(JScrollPane)。
2.2.1 卡片布局与选项卡面板
卡片布局是一种布局管理器,它允许在同一个位置显示多个组件,但一次只显示一个。选项卡面板(JTabbedPane)则是一个复合组件,它允许通过选项卡切换不同的面板视图,每个面板代表了一个页面或一个视图。
import javax.swing.*;
import java.awt.*;
public class CardLayoutTabbedPaneDemo extends JFrame {
private CardLayout cardLayout;
private JPanel cardPanel;
private JTabbedPane tabbedPane;
private JPanel[] panels;
public CardLayoutTabbedPaneDemo() {
// 创建卡片布局
cardLayout = new CardLayout();
// 创建面板
cardPanel = new JPanel(cardLayout);
// 创建选项卡面板
tabbedPane = new JTabbedPane();
// 初始化面板数组
panels = new JPanel[] {
new JPanel(), // 第一个面板
new JPanel(), // 第二个面板
new JPanel() // 第三个面板
};
// 填充面板内容
for (JPanel panel : panels) {
panel.add(new JLabel("这是面板 " + Arrays.toString(panels).indexOf(panel)));
panel.setBorder(BorderFactory.createTitledBorder("面板 " + Arrays.toString(panels).indexOf(panel)));
}
// 添加面板到选项卡面板
for (int i = 0; i < panels.length; i++) {
tabbedPane.addTab("标签 " + i, panels[i]);
}
// 将选项卡面板添加到卡片面板
cardPanel.add(tabbedPane);
// 设置窗口布局
setLayout(new BorderLayout());
// 添加卡片面板到窗口
add(cardPanel, BorderLayout.CENTER);
// 设置窗口的其他属性
setTitle("卡片布局与选项卡面板示例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CardLayoutTabbedPaneDemo();
}
});
}
}
在该示例中,我们创建了一个卡片布局面板,并在其中嵌入了一个选项卡面板。选项卡面板包含三个不同的面板,每个面板都使用了TitledBorder边框来添加标题。通过CardLayout的show方法,我们可以控制选项卡面板中显示的特定面板。
2.2.2 分隔面板与滑动面板的综合运用
分隔面板(JDesktopPane)通常用于复杂的桌面应用程序中,以实现窗口组件的拖动和停靠功能,而滑动面板(JScrollPane)则用于处理组件的滚动视图,比如文本区域或者列表组件。
import javax.swing.*;
import java.awt.*;
public class SplitPaneScrollPaneDemo extends JFrame {
private JDesktopPane desktopPane;
private JTextArea textArea;
private JScrollPane scrollPane;
public SplitPaneScrollPaneDemo() {
// 创建桌面面板
desktopPane = new JDesktopPane();
// 创建文本区域
textArea = new JTextArea(15, 30);
// 创建滚动面板
scrollPane = new JScrollPane(textArea);
// 添加滚动面板到桌面面板
desktopPane.add(scrollPane, JLayeredPane.DEFAULT_LAYER);
// 设置窗口布局
setLayout(new BorderLayout());
// 添加桌面面板到窗口
add(desktopPane, BorderLayout.CENTER);
// 设置窗口的其他属性
setTitle("分隔面板与滑动面板示例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SplitPaneScrollPaneDemo();
}
});
}
}
在分隔面板与滑动面板的综合运用中,我们创建了一个JDesktopPane,并在其上添加了一个JScrollPane,后者包含了文本区域组件。JScrollPane能够自动处理文本区域的滚动,当文本内容超出可视区域时,滚动条会相应出现。
分隔面板与滑动面板的综合运用可以提供更佳的用户体验,尤其在需要显示大量文本或者列表等需要滚动查看的界面时,显得尤为有用。
复合组件在Swing库中提供了更多的灵活性和复杂性,它们能够让开发者以更少的代码和更高效的方式构建出复杂的用户界面。通过组合基础组件和使用特定的布局管理器,开发者可以创建功能丰富的应用程序界面。
2.3 特殊组件的高级应用
特殊组件在Swing库中提供了更多的交互性和视觉效果。它们包括进度条、滑动条、菜单栏和工具栏等。本节将深入探讨这些组件的应用,并展示如何定制和实践这些组件。
2.3.1 进度条和滑动条的深入探讨
进度条(JProgressBar)和滑动条(JSlider)提供了显示数据变化和让用户进行调节的界面元素。进度条通常用于显示任务的完成度,而滑动条则允许用户通过滑动来选择数值。
import javax.swing.*;
import java.awt.*;
public class ProgressBarSliderDemo extends JFrame {
private JProgressBar progressBar;
private JSlider slider;
public ProgressBarSliderDemo() {
// 创建进度条
progressBar = new JProgressBar(0, 100);
// 创建滑动条
slider = new JSlider(JSlider.HORIZONTAL, 0, 100, 50);
// 设置窗口布局
setLayout(new GridLayout(2, 1));
// 添加进度条和滑动条到窗口
add(progressBar);
add(slider);
// 设置窗口的其他属性
setTitle("进度条和滑动条示例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
setVisible(true);
// 为滑动条添加事件监听器
slider.addChangeListener(e -> {
progressBar.setValue(slider.getValue());
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ProgressBarSliderDemo();
}
});
}
}
在此示例中,我们创建了一个JProgressBar和一个JSlider,并将它们添加到了一个窗口中。同时,我们为滑动条添加了一个状态变化监听器,以便用户通过拖动滑块来更新进度条的值。
2.3.2 菜单栏和工具栏的定制与实践
菜单栏(JMenuBar)和工具栏(JToolBar)为应用程序提供了组织良好的命令集合。菜单栏通常位于窗口顶部,包含多个下拉菜单,而工具栏则提供快速访问常用功能的按钮。
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MenuBarToolBarDemo extends JFrame {
private JMenuBar menuBar;
private JToolBar toolBar;
private JButton newButton;
private JButton openButton;
public MenuBarToolBarDemo() {
// 创建菜单栏和工具栏
menuBar = new JMenuBar();
toolBar = new JToolBar();
// 创建新按钮
newButton = new JButton("新建");
newButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("新建操作");
}
});
// 创建打开按钮
openButton = new JButton("打开");
openButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("打开操作");
}
});
// 将按钮添加到工具栏
toolBar.add(newButton);
toolBar.add(openButton);
// 创建文件菜单
JMenu fileMenu = new JMenu("文件");
JMenuItem newMenuItem = new JMenuItem("新建");
JMenuItem openMenuItem = new JMenuItem("打开");
newMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("菜单新建操作");
}
});
openMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("菜单打开操作");
}
});
// 将菜单项添加到文件菜单
fileMenu.add(newMenuItem);
fileMenu.add(openMenuItem);
// 将菜单添加到菜单栏
menuBar.add(fileMenu);
// 设置窗口布局
setLayout(new BorderLayout());
// 将菜单栏添加到窗口
setJMenuBar(menuBar);
// 将工具栏添加到窗口的北部
add(toolBar, BorderLayout.NORTH);
// 设置窗口的其他属性
setTitle("菜单栏和工具栏示例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 300);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MenuBarToolBarDemo();
}
});
}
}
在这个示例中,我们创建了一个菜单栏和工具栏,并将它们添加到窗口中。我们添加了两个按钮到工具栏,并创建了文件菜单及其子菜单项。菜单项和按钮都绑定了事件监听器,以便在用户操作时执行相应的操作。
通过菜单栏和工具栏,我们可以让用户通过图形化界面来执行应用程序的命令,这比命令行界面更加直观和易于使用。
特殊组件的高级应用让我们能够构建出更加动态和交互式的用户界面。通过以上示例,我们可以了解到如何使用这些组件来实现特定的功能,以及如何通过编程逻辑来响应用户的操作。这为我们的Swing应用程序增添了更多的功能性和灵活性。
3. 布局管理器的应用
布局管理器是Swing和AWT图形用户界面库中用于管理组件位置和大小的工具。理解布局管理器的工作原理对于创建动态响应的用户界面至关重要。本章节将详细介绍布局管理器的基本原理、综合应用以及高级自定义技巧。
3.1 布局管理器的基本原理
布局管理器能够自动管理组件的大小和位置,这意味着用户界面可以适应不同的屏幕尺寸和分辨率。Swing提供了多种内置的布局管理器,每种都具有不同的布局策略。
3.1.1 边界布局(BorderLayout)的使用
边界布局是Swing中使用最为广泛的布局之一,它将容器分为五个部分:北(NORTH)、南(SOUTH)、东(EAST)、西(WEST)和中(CENTER)。组件按方向布局,并且可以根据容器的大小自动扩展或收缩。
import javax.swing.*;
public class BorderLayoutExample {
public static void main(String[] args) {
JFrame frame = new JFrame("BorderLayout Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setLayout(new BorderLayout());
JButton northButton = new JButton("North");
JButton southButton = new JButton("South");
JButton eastButton = new JButton("East");
JButton westButton = new JButton("West");
JButton centerButton = new JButton("Center");
frame.add(northButton, BorderLayout.NORTH);
frame.add(southButton, BorderLayout.SOUTH);
frame.add(eastButton, BorderLayout.EAST);
frame.add(westButton, BorderLayout.WEST);
frame.add(centerButton, BorderLayout.CENTER);
frame.setVisible(true);
}
}
在这段代码中,我们创建了一个窗口并设置了边界布局,然后添加了五个按钮分别放置在五个不同的区域。
3.1.2 流布局(FlowLayout)的设计规则
流布局是一种简单直观的布局管理器,它从左到右、从上到下地放置组件,就像在阅读书籍时一样。当容器的宽度不足以放下下一个组件时,它会换行继续布局。
import javax.swing.*;
public class FlowLayoutExample {
public static void main(String[] args) {
JFrame frame = new JFrame("FlowLayout Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setLayout(new FlowLayout());
for (int i = 0; i < 10; i++) {
frame.add(new JButton("Button " + i));
}
frame.setVisible(true);
}
}
这段代码展示了一个窗口应用流布局管理器,并添加了十个按钮,这些按钮将会在窗口中顺序排列。
3.2 布局管理器的综合应用
在实际的开发中,往往需要将不同的布局管理器综合运用以满足复杂的界面布局需求。
3.2.1 网格布局(GridBagLayout)的技巧
网格布局是Swing中最为强大的布局管理器之一,它允许组件放置在行和列的任意格中,并且可以指定组件在格中占用的行数和列数。
import javax.swing.*;
import java.awt.*;
public class GridBagLayoutExample {
public static void main(String[] args) {
JFrame frame = new JFrame("GridBagLayout Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0; // 列位置
gbc.gridy = 0; // 行位置
panel.add(new JButton("Button 1"), gbc);
gbc.gridx = 1;
gbc.gridy = 0;
panel.add(new JCheckBox("Check Box"), gbc);
// 其他组件的添加...
frame.add(panel);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
这段代码创建了一个按钮和一个复选框,并使用 GridBagConstraints 指定了它们在网格中的位置。
3.2.2 网格包布局(GridBagLayout)的案例分析
在使用网格布局时,需要细心规划组件的位置和大小。以下是一个案例分析,展示如何使用网格布局创建一个复杂的窗口界面。
// ...之前的代码...
// 假设我们已经有了许多组件的引用以及它们对应的gbc设置...
// 添加组件到panel
panel.add(new JTextField(15), new GridBagConstraints(0, 1, 3, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0));
// 更多组件添加...
// 添加panel到frame
frame.add(panel, BorderLayout.CENTER);
// ...之后的代码...
在这个例子中,我们添加了一个文本框组件到panel,并通过 GridBagConstraints 精确控制了其在网格中的位置和大小。
3.3 布局管理器的高级自定义
当内置布局管理器无法满足特定的需求时,可以通过自定义布局管理器来实现更复杂的布局策略。
3.3.1 编写自定义布局管理器的步骤
编写一个自定义布局管理器需要实现 LayoutManager 接口,并重写其方法以根据容器的大小改变组件的布局。
import javax.swing.*;
import java.awt.*;
public class CustomLayout 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(100, 100);
}
@Override
public Dimension minimumLayoutSize(Container parent) {
// 返回容器的最小布局大小
return new Dimension(50, 50);
}
@Override
public void layoutContainer(Container parent) {
// 实现布局逻辑
}
}
这段代码提供了一个自定义布局管理器的框架,你需要在 layoutContainer 方法中实现具体的布局逻辑。
3.3.2 自定义布局管理器的案例演练
这里是一个简单的自定义布局管理器的案例,它将组件以圆形的方式排列在容器中。
// ...之前的代码...
JPanel centerPanel = new JPanel(new CustomLayout());
// 添加组件到centerPanel
frame.add(centerPanel, BorderLayout.CENTER);
// ...之后的代码...
在这个例子中,我们创建了一个 CustomLayout 实例,并将其设置到一个 JPanel 中。随后,我们向这个panel添加了几个组件,它们将以自定义的圆形方式排列。
本章通过介绍布局管理器的不同应用和实践案例,展现了布局管理器在Swing界面开发中的重要性和灵活性。下一章将继续深入事件处理机制,探讨如何使界面响应用户交互。
4. 事件处理机制
4.1 事件处理的基本概念
4.1.1 事件监听器的原理和种类
在Java的Swing组件中,事件监听器(Listener)是一种机制,它允许我们为组件添加特定的事件处理行为。当事件发生时,例如用户点击按钮或按下键盘,相应的监听器会接收到一个事件对象,该对象包含了事件的详细信息,如事件类型和发生的时间。
事件监听器的原理基于观察者模式(Observer Pattern),其中一个对象(观察者)监听另一个对象(被观察者)的状态变化,并在状态变化时得到通知。在Swing中,组件就是被观察者,它们生成事件;监听器则是观察者,它们响应事件。
Java为不同的事件类型提供了不同的监听器接口,例如:
ActionListener:响应动作事件,如按钮点击。KeyListener:响应键盘事件,如按键按下和释放。MouseListener:响应鼠标事件,如点击、进入组件等。FocusListener:响应焦点事件,如组件获得或失去焦点。
每个接口都有一系列方法,这些方法必须被实现以响应不同的事件。例如, ActionListener 只有一个 actionPerformed 方法,该方法在动作事件发生时被调用。
4.1.2 常用事件处理接口的实现
实现事件监听器通常需要以下几个步骤:
- 创建一个监听器类,该类实现一个或多个事件监听器接口。
- 在类中实现接口中定义的方法,以响应事件。
- 创建监听器对象,并将它注册到相应的组件上。
以下是一个简单的按钮点击事件监听器实现的例子:
import javax.swing.*;
import java.awt.event.*;
public class ButtonClickListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button clicked!");
}
public static void main(String[] args) {
JFrame frame = new JFrame("Event Handling Example");
JButton button = new JButton("Click Me");
// 实例化监听器并注册到按钮上
ButtonClickListener listener = new ButtonClickListener();
button.addActionListener(listener);
frame.getContentPane().add(button);
frame.setSize(200, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
在上面的例子中, ButtonClickListener 类实现了 ActionListener 接口,并重写了 actionPerformed 方法。当按钮被点击时,控制台会打印出“Button clicked!”。
事件监听器可以在创建组件的同时注册,也可以在组件创建之后注册。后者提供了一种更为灵活的方式来管理事件监听器,尤其是在复杂的用户界面中。
5. 对话框的使用
在图形用户界面(GUI)编程中,对话框是一个非常重要的部分,它允许应用程序与用户进行交互,获取用户输入或者展示重要信息。对话框可以分为标准对话框和自定义对话框两大类,每一种都有其特定的用途和设计原则。在Java中,Swing库提供了丰富的API来帮助开发者快速有效地创建对话框。在本章节中,我们将深入了解如何使用Java Swing来创建和利用对话框。
5.1 标准对话框的应用
标准对话框是由Swing库预定义的对话框类型,包括消息对话框、文件选择对话框、颜色选择对话框等。这些对话框为开发者提供了一个快速实现常用交互的便捷途径,同时也保证了用户体验的一致性。
5.1.1 消息对话框(MessageDialog)的实现
消息对话框用于向用户显示一些消息信息,并且根据用户的选择做出响应。在Java中,可以使用 JOptionPane 类来创建消息对话框。
import javax.swing.JOptionPane;
public class MessageDialogExample {
public static void main(String[] args) {
// 显示一个简单的消息对话框
JOptionPane.showMessageDialog(null, "这是一个消息对话框。",
"消息标题", JOptionPane.INFORMATION_MESSAGE);
}
}
在上述代码中, showMessageDialog 方法是一个静态方法,它接受四个参数:父组件、消息内容、对话框标题以及消息类型。父组件参数可以为 null ,表示对话框没有父组件,将采用默认的窗口装饰。消息类型参数定义了对话框的图标类型。
5.1.2 文件选择对话框(FileChooserDialog)的定制
文件选择对话框允许用户选择一个文件或者目录。 JFileChooser 类提供了一个文件选择对话框的实现。
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
public class FileChooserDialogExample {
public static void main(String[] args) {
JFileChooser fileChooser = new JFileChooser();
// 添加一个文件过滤器,只显示特定类型的文件
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"JPEG & GIF Images", "jpg", "gif");
fileChooser.setFileFilter(filter);
int userSelection = fileChooser.showOpenDialog(null);
if (userSelection == JFileChooser.APPROVE_OPTION) {
System.out.println("选择的文件:" + fileChooser.getSelectedFile().getAbsolutePath());
} else {
System.out.println("未选择文件");
}
}
}
在这个例子中,我们创建了一个 JFileChooser 实例,并设置了一个文件过滤器,只显示JPEG和GIF格式的图片。接着调用 showOpenDialog 方法来显示文件选择对话框。如果用户选择了文件并且点击了确认按钮, getSelectedFile 方法将返回用户选择的文件。
5.2 自定义对话框的开发
在某些情况下,标准对话框并不能满足特定的交互需求,这时就需要自定义对话框。自定义对话框可以由开发者完全控制其外观和行为。
5.2.1 对话框设计的基本原则
自定义对话框的设计应当遵循以下原则:
- 简洁性 :确保对话框界面干净整洁,避免过多干扰用户的信息。
- 一致性 :保持对话框的布局和行为与应用程序的其他部分一致。
- 明确性 :明确指示用户需要进行的操作和可以采取的行动。
- 响应性 :确保用户与对话框的交互能够及时得到反馈。
5.2.2 创建模态对话框和非模态对话框的实例
模态对话框要求用户先对对话框做出回应,然后才能继续与应用程序的其他部分交互。 JDialog 类可以用来创建模态对话框。
import javax.swing.JDialog;
import javax.swing.JFrame;
public class ModalDialogExample {
public static void main(String[] args) {
// 创建一个模态对话框
JDialog dialog = new JDialog(new JFrame(), "模态对话框", true);
dialog.add(new javax.swing.JLabel("这是一个模态对话框。"));
dialog.setSize(300, 200);
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
}
}
在这个例子中, JDialog 的构造函数中的 true 参数表示对话框是模态的。当对话框显示时,用户必须首先关闭它才能与创建它的窗口进行交互。
非模态对话框允许用户在不关闭对话框的情况下与其他界面元素交互。
import javax.swing.JDialog;
import javax.swing.JFrame;
public class NonModalDialogExample {
public static void main(String[] args) {
// 创建一个非模态对话框
JDialog dialog = new JDialog(new JFrame(), "非模态对话框", false);
dialog.add(new javax.swing.JLabel("这是一个非模态对话框。"));
dialog.setSize(300, 200);
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
// 继续执行其他代码
System.out.println("非模态对话框可以与主窗口同时使用。");
}
}
在这个例子中, JDialog 的构造函数中的 false 参数表示对话框是非模态的。因此,主程序可以继续执行,而不是等待对话框关闭。
5.3 对话框的高级应用
高级应用主要关注对话框中事件监听和响应机制,以及如何有效地传递数据和处理结果。
5.3.1 对话框中事件监听和响应机制
自定义对话框中的事件监听和响应通常需要使用事件监听器模式。以下是一个事件监听器接口的简单实现示例:
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class EventHandlingExample {
public static void main(String[] args) {
// 创建一个对话框
JDialog dialog = new JDialog(new JFrame(), "事件处理对话框", true);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setSize(300, 200);
// 添加标签和按钮
JLabel label = new JLabel("点击按钮,更新标签文本");
JButton button = new JButton("更新文本");
// 将组件添加到对话框中
dialog.getContentPane().add(label);
dialog.getContentPane().add(button);
// 为按钮添加事件监听器
button.addActionListener(e -> label.setText("文本已更新"));
// 显示对话框
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
}
}
这段代码演示了如何为一个按钮添加一个动作监听器,当按钮被点击时,监听器会被触发,并更新标签的文本内容。
5.3.2 对话框数据传递和结果处理
对话框通常需要向调用它们的组件传递数据或结果。这可以通过回调函数或者使用 Dialog 类返回的值来实现。
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class DataTransferExample {
public static void main(String[] args) {
JDialog dialog = new JDialog(new JFrame(), "数据传递对话框", true);
dialog.add(new javax.swing.JLabel("输入一些文本:"));
dialog.setSize(300, 100);
dialog.setLocationRelativeTo(null);
// 添加输入框和获取输入值的按钮
JButton button = new JButton("获取文本");
dialog.getContentPane().add(button);
// 显示对话框并等待用户响应
dialog.setVisible(true);
// 获取用户输入并处理
Object result = JOptionPane.showInputDialog(dialog, "请输入文本:");
if (result != null) {
System.out.println("用户输入的文本:" + result.toString());
}
}
}
在上面的示例中,我们使用了 JOptionPane.showInputDialog 方法来获取用户输入的文本。这个方法会返回用户输入的数据,如果用户取消了输入框,则返回 null 。
通过这些例子,我们展示了如何在Java Swing中使用标准对话框以及如何开发和运用自定义对话框。对话框作为GUI应用程序中不可或缺的一部分,掌握其应用能显著提升应用程序的交互质量和用户体验。
6. 自定义组件的开发
6.1 组件继承和扩展
6.1.1 继承现有的组件进行定制
在Java中,Swing库提供的组件往往不能满足所有需求,这时可以通过继承已有组件来实现定制。例如,我们需要一个带有特殊提示信息的文本框,可以通过继承 JTextField 并重写相应的构造函数和方法来实现。
public class HintTextField extends JTextField {
private String hint;
public HintTextField(String hint) {
super();
this.hint = hint;
updateHint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (getText().isEmpty()) {
g.drawString(hint, getInsets().left, g.getFontMetrics().getMaxAscent());
}
}
public void updateHint() {
if (getText().isEmpty()) {
setForeground(Color.GRAY);
setText(hint);
} else {
setForeground(Color.BLACK);
setText("");
}
}
}
继承并扩展组件时,我们通常需要关注如何处理状态变化,如上面示例中,文本框内容改变时,提示信息的显示与否也跟着变化。
6.1.2 组件绘制原理与重绘策略
自定义组件的绘制原理涉及 paintComponent 方法,该方法是所有JComponent组件绘制的基础。重绘策略则需要考虑何时组件需要重新绘制,通常是通过调用 repaint() 方法来实现。
@Override
public void repaint(long tm, int x, int y, int width, int height) {
// 定义组件重绘的矩形区域,仅重绘变化的部分以提升性能
super.repaint(tm, x, y, width, height);
}
6.2 组件的高级定制技巧
6.2.1 使用JComponent自定义绘制组件
在Swing中, JComponent 类提供了丰富的API供开发者使用,以便进行高度的自定义。例如,我们想要一个能够显示不同天气信息的自定义组件,可以这样设计:
public class WeatherComponent extends JComponent {
// 组件绘制代码略
public void updateWeatherIcon(ImageIcon icon) {
// 更新天气图标
repaint();
}
}
绘制时,需要处理好组件的尺寸、边距,以及可能的重叠绘制问题。
6.2.2 处理组件的布局属性和事件
除了外观上的定制,组件的布局属性和事件处理也是高级定制的一部分。例如,为组件添加鼠标事件监听器,以支持鼠标悬停、点击等事件。
public class CustomButton extends JButton {
public CustomButton(String label) {
super(label);
// 添加鼠标事件监听
addMouseListener(new MouseAdapter() {
public void mouseEntered(MouseEvent e) {
// 鼠标进入按钮区域时的处理
}
public void mouseExited(MouseEvent e) {
// 鼠标离开按钮区域时的处理
}
});
}
}
6.3 组件在实际项目中的应用
6.3.1 组件封装与代码复用
在实际项目中,自定义组件需要高内聚和低耦合,便于封装和代码复用。通常会将自定义组件封装在一个单独的包或模块中,其他模块通过公共API与之交互。
// 模块中定义组件的公共方法
public class CustomComponentPackage {
public static WeatherComponent getWeatherComponent() {
// 创建并返回自定义天气组件
return new WeatherComponent();
}
}
6.3.2 组件性能优化与调试经验
在组件开发中性能优化也很关键,这包括对重绘事件的管理、使用硬件加速等技术手段。调试经验则需要注重对组件生命周期的理解,以及常见问题的排查方法。
// 在组件销毁前释放资源,优化性能
public void destroy() {
// 清理资源,比如监听器等
}
在调试时,关注组件的更新频率,避免过度重绘,并对组件进行单元测试以保证稳定性和可靠性。
简介:Java Swing和AWT库是用于开发具有丰富交互式用户界面的桌面应用程序。AWT作为基础GUI库,提供与操作系统集成的组件,而Swing在AWT之上,提供跨平台一致性更强的轻量级组件。本课程将通过100多个案例带你深入学习从基础到高级的Java图形用户界面编程技术,涵盖组件、布局、事件处理、对话框、菜单、表格、树、面板、MVC模式、国际化和定制组件等。通过实践这些案例,你将掌握如何使用Swing和AWT构建高效、美观的应用程序。
更多推荐



所有评论(0)