Swing图形界面编程深入解析与案例分析

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Swing是Java的一个图形用户界面工具包,属于Java Foundation Classes(JFC)。它提供了丰富的组件库,支持事件驱动编程和MVC设计模式,适用于构建功能强大的桌面应用程序。王鹏的源码分享包括了Swing布局、组件使用、事件处理、菜单栏和快捷键创建、键盘和鼠标事件处理以及国际化等方面的案例详解。深入学习Swing还包括了解SwingWorker、MDI应用、自定义绘图与特效等高级主题。通过实际案例学习,开发者可以掌握Swing组件和机制,提升编程技能,构建高质量的桌面应用。 Swing 王鹏

1. Swing图形用户界面概述

1.1 Swing框架简介

Swing是一个用于开发Java应用程序图形用户界面的工具包。自Java 1.1版本起,Swing成为了Java标准版的一部分,提供了丰富的用户界面组件,用于构建跨平台的桌面应用程序。Swing基于AWT(Abstract Window Toolkit)构建,相比AWT,Swing提供了一套更完整的GUI组件。

1.2 Swing与AWT的关系

AWT是Java最早的图形用户界面工具包,而Swing在AWT的基础上进一步扩展。Swing组件大多数是轻量级的,意味着它们不需要依赖本地操作系统提供的原生组件。这一点与AWT组件(重量级组件)形成了对比,后者在不同平台上可能表现出不同的外观和行为。

1.3 Swing的优势与应用场景

Swing的主要优势在于它的一致性和可扩展性。通过使用Swing,开发者能够创建出在所有主流操作系统上具有一致外观和行为的应用程序。它支持丰富的用户界面元素,如按钮、文本框、滑动条等,并且还可以轻松地通过扩展JComponent来自定义新的组件。Swing适用于需要高度交互性的桌面应用程序开发。

// 示例:Swing的简单应用
import javax.swing.*;

public class SwingApp {
    public static void main(String[] args) {
        // 创建 JFrame 实例
        JFrame frame = new JFrame("Swing Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setVisible(true);
    }
}

该代码段展示了Swing应用的基础结构,其中 JFrame 是一个顶层窗口容器,用于创建应用程序的主窗口。

2. 组件库使用与布局管理

2.1 Swing组件库概览

Swing库为Java提供了一套全面的GUI组件,用于构建具有本地外观的应用程序。Swing组件不仅功能丰富,而且高度可定制,可以满足从简单的工具栏到复杂的多面板窗口的各种界面需求。

2.1.1 核心组件分类

Swing组件分为多个层次,最基本的有JComponent、JFrame、JPanel等。它们是构成更复杂组件的基础。例如,JButton是JComponent的子类,而JTextField、JLabel等都是JComponent的扩展。

// 示例代码:创建一个按钮
JButton button = new JButton("Click Me");

在上述示例中, JButton 是一个基本的Swing组件,它继承自 JComponent 类,提供了一个按钮,上面有文本“Click Me”。Swing组件都是通过构造函数进行初始化,并可以进行进一步的配置。

Swing组件库中的组件可以大致分为以下几类:

  • 输入组件 :如JTextField、JPasswordfield、JComboBox等,用于接收用户的输入。
  • 选择组件 :如JCheckBox、JRadioButton等,用于提供选择功能。
  • 显示组件 :如JLabel、JProgressBar等,用于显示信息。
  • 容器组件 :如JFrame、JPanel等,用于组织其他组件。
2.1.2 组件的创建与初始化

在Swing中,组件的创建和初始化通常包括以下几个步骤:

  1. 导入必要的Swing组件类。
  2. 实例化组件。
  3. 配置组件属性,如大小、字体、颜色等。
  4. 将组件添加到布局管理器中。
  5. 最后,使组件可见。
// 示例代码:创建一个窗口并添加一个按钮
public class MainFrame extends JFrame {
    public MainFrame() {
        this.setTitle("Swing Demo");
        this.setSize(300, 200);
        JButton button = new JButton("Click Me");
        this.getContentPane().add(button);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new MainFrame();
            }
        });
    }
}

在上面的代码中, MainFrame 类继承自 JFrame 。在构造函数中,我们设置了窗口的标题和大小,并创建了一个按钮。按钮被添加到 JFrame 的内容面板中,然后窗口被设置为可见。

2.2 布局管理器的使用

Swing提供了一系列的布局管理器来帮助开发者组织界面中的组件。布局管理器可以自动调整组件的大小和位置,以适应不同的窗口大小和分辨率。

2.2.1 不同布局管理器的特点

Swing提供了多种布局管理器,包括:

  • BorderLayout :将组件放置在容器的北、南、东、西和中心位置。
  • FlowLayout :按照组件在代码中声明的顺序,从左到右排列,并且一行满了就换行。
  • GridLayout :将容器分成一个网格,并将组件放入网格中。
  • GridBagLayout :允许组件在网格中进行更复杂的定位。
  • CardLayout :在同一个位置显示一个组件,其他组件则隐藏。

每种布局管理器都有其适用的场景,例如 BorderLayout 通常用于创建复杂窗口的框架,而 FlowLayout 适用于创建简单的工具栏或按钮栏。

2.2.2 布局管理器的选择策略

选择合适的布局管理器可以简化界面的设计过程,并使界面更加灵活。例如,如果窗口需要在中间显示一个大型组件,并且在边缘有少量的控制按钮,那么 BorderLayout 会是一个好的选择。

对于简单的表单, GridLayout 可以使界面看起来整洁、有序。相反,如果界面需要复杂和灵活的组件对齐方式, GridBagLayout 提供了更多自由度。

2.2.3 嵌套布局的设计思路

嵌套布局是在布局管理器中使用其他布局管理器来实现复杂的布局。对于复杂的界面,合理的布局嵌套可以帮助开发者更好地组织组件。

例如,可以使用 BorderLayout 作为主容器的布局管理器,然后在中间位置使用 GridBagLayout 来精细控制组件的布局。

// 示例代码:嵌套布局的简单实现
public class NestedLayoutFrame extends JFrame {
    public NestedLayoutFrame() {
        this.setLayout(new BorderLayout());

        JPanel panelNorth = new JPanel(new FlowLayout(FlowLayout.LEFT));
        panelNorth.add(new JLabel("North Panel"));
        JPanel panelCenter = new JPanel(new GridLayout(3, 1));
        panelCenter.add(new JButton("Button 1"));
        panelCenter.add(new JButton("Button 2"));
        panelCenter.add(new JButton("Button 3"));

        this.add(panelNorth, BorderLayout.NORTH);
        this.add(panelCenter, BorderLayout.CENTER);
        this.setSize(300, 200);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new NestedLayoutFrame();
            }
        });
    }
}

在嵌套布局的示例中,我们创建了一个 JFrame 使用 BorderLayout 作为主布局。我们在北方使用 FlowLayout 添加了一个标签,在中心位置使用 GridLayout 添加了三个按钮。这种布局允许我们在界面的不同部分使用不同的布局策略。

表格:不同布局管理器的对比

| 布局管理器 | 特点 | 适用场景 | | --- | --- | --- | | BorderLayout | 分为五个区域,组件可以填满整个区域 | 复杂的窗口框架 | | FlowLayout | 从左到右,从上到下排列组件 | 简单的按钮栏或工具栏 | | GridLayout | 将容器分成固定大小的网格,组件占据一个或多个单元格 | 用于表单和网格结构 | | GridBagLayout | 更灵活的网格布局,可以指定组件的填充和对齐方式 | 需要复杂组件定位的场景 | | CardLayout | 只显示一个组件,其他组件隐藏 | 选项卡界面或向导式的用户交互 |

选择合适的布局管理器,能够根据需要灵活调整组件大小和位置,是构建用户友好界面的关键。在实际开发中,开发者可能需要结合多种布局管理器来完成复杂的界面设计。

这一章节的内容展示了Swing组件库的概览,包括核心组件的分类和创建初始化方法,并详细介绍了不同布局管理器的特点、选择策略和嵌套布局的设计思路。通过这些基础知识,开发者可以有效地利用Swing库来构建丰富的用户界面。

3. 事件驱动编程模型

在Swing应用程序中,事件驱动编程模型是核心概念之一。事件处理机制保证了用户界面响应用户操作的能力,是实现交互性的基石。本章节深入探讨Swing中的事件处理机制,并提供实践技巧,以便开发者能够高效地编写出能够响应用户操作的GUI应用程序。

3.1 事件处理机制

3.1.1 事件监听器的注册与使用

在Swing框架中,几乎所有的用户交互都通过事件机制来处理。事件监听器是实现事件响应的关键。通过注册事件监听器,我们能够让组件对特定类型的事件做出响应。

// 示例代码:注册按钮点击事件监听器
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ButtonExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Button Example");
        JButton button = new JButton("Click Me!");

        // 添加ActionListener
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(frame, "Button clicked!");
            }
        });

        frame.add(button);
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

在上述代码中,我们创建了一个按钮,并为其注册了一个 ActionListener 。当按钮被点击时, actionPerformed 方法会被触发,弹出一个对话框来通知用户按钮已被点击。

参数说明:
  • ActionEvent :是用户界面事件的超类,例如按钮点击、菜单项选择等。
  • actionPerformed :为 ActionListener 接口中的方法,用于响应触发事件。

事件监听器可以通过匿名类或者Lambda表达式(Java 8及以上版本)来实现,使得代码更加简洁。

3.1.2 事件传播与消费过程

事件在Swing中传播时遵循特定的顺序和规则,理解这一过程对于构建出用户友好的应用程序至关重要。

事件传播顺序

当事件被触发时,Swing首先检查是否有当前组件的监听器感兴趣于这个事件。如果有,事件就传递给监听器处理。如果当前组件没有处理事件,则会将事件传播到它的父组件,直到事件被处理或到达容器的顶部。

消费事件

在事件监听器中, actionPerformed 方法内,一旦完成所需的操作,你可以通过返回一个值或者抛出一个异常来指示事件是否已被“消费”。对于 ActionEvent ,通常在处理完毕后不需要消费事件,除非要阻止事件继续向上层传播。

// 示例代码:消费事件示例
button.addActionListener(e -> {
    // 消费事件
    e.consume();
    System.out.println("Event consumed!");
});

3.2 事件处理的实践技巧

3.2.1 常见事件类型及其应用场景

Swing提供了多种事件类型来响应不同的用户操作,例如鼠标事件、键盘事件、窗口事件等。开发者需要根据应用场景选择合适的事件类型。

// 示例代码:鼠标点击事件监听器
button.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseClicked(MouseEvent e) {
        if (e.getButton() == MouseEvent.BUTTON1) {
            // 鼠标左键点击的逻辑
            System.out.println("Mouse clicked with left button!");
        }
    }
});
表格:常用事件类型及其描述

| 事件类型 | 描述 | | --- | --- | | ActionEvent | 用户界面的点击事件,如按钮点击 | | MouseEvent | 鼠标操作事件,如点击、移动、拖拽 | | KeyEvent | 键盘输入事件,包括按键按下和释放 | | WindowEvent | 窗口状态事件,如打开、关闭、激活 |

3.2.2 事件处理的性能优化方法

随着用户界面复杂度的增加,事件处理逻辑也可能变得复杂,从而影响性能。以下是一些性能优化的建议:

  • 事件解耦 :将事件的处理分散到不同的方法中,避免在单个监听器方法中执行过多操作。
  • 使用合适的事件 :根据需要使用适当的事件类型。例如,对于连续动作,使用事件类型而不是帧循环。
  • 线程优化 :对于需要大量计算的操作,考虑使用 SwingWorker 或将其放在事件分发线程(EDT)之外执行,以避免阻塞UI。
// 使用SwingWorker进行后台操作以提高性能
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
    @Override
    protected Void doInBackground() throws Exception {
        // 这里执行耗时操作
        Thread.sleep(3000);
        return null;
    }

    @Override
    protected void done() {
        //耗时操作完成后更新UI
        JOptionPane.showMessageDialog(frame, "Background task completed!");
    }
};
worker.execute();

通过上述代码,可以将耗时的后台任务放在一个单独的线程中执行,从而不会阻塞事件分发线程。

在本章节中,我们深入了解了Swing事件处理机制的核心概念和实践技巧。我们探讨了如何注册和使用事件监听器,以及事件是如何在组件之间传播的。接着,我们通过表格详细介绍了常见事件类型及其应用场景,并讨论了性能优化的方法。这些知识将帮助开发者构建更高效和响应灵敏的Swing应用程序。

4. 模型-视图-控制器(MVC)设计模式

4.1 MVC设计模式基础

4.1.1 MVC模式的组件和职责

模型-视图-控制器(MVC)设计模式是一种广泛应用于图形用户界面(GUI)开发的架构模式。MVC将应用划分为三个主要的组件:模型(Model)、视图(View)和控制器(Controller),每个组件负责处理应用的不同方面。

  • 模型(Model) :是应用的“数据核心”,负责管理和维护数据,响应数据变化的逻辑。它代表了业务数据和业务逻辑的处理。在Swing中,模型通常是指实现了特定功能的Java对象。
  • 视图(View) :是用户界面部分,负责数据的展示和用户交互。它将数据以用户友好的方式展示,如窗口、按钮等。Swing中的JPanel、JFrame等都可看作是视图组件。

  • 控制器(Controller) :作为模型和视图之间的中介,负责接收用户的输入并调用模型和视图去完成相应的更新。在MVC模式中,控制器解释用户的输入,使其转换为对模型或视图的修改。

这种分离确保了应用的可扩展性、可维护性和可测试性,而且有利于团队分工开发,其中,前端开发者负责视图,后端开发者负责模型,而控制器则作为二者沟通的桥梁。

4.1.2 MVC模式在Swing中的实现

在Swing应用中,MVC模式的实现会根据具体的需求和设计来调整。一般来说,可以按照以下方式将MVC模式映射到Swing组件中:

  • 模型(Model) :通常对应于数据处理相关的Java类。例如,如果正在开发一个联系人管理系统,那么联系人对象及其相关的业务逻辑就构成了模型。

  • 视图(View) :在Swing中,视图通常指包含各种组件(如JLabel、JButton、JTable等)的JPanel或整个JFrame窗口。

  • 控制器(Controller) :控制器代码通常存在于事件监听器中,这些监听器被添加到视图组件上。当用户与视图交云时,相关的事件监听器被触发,执行相应的逻辑来更新模型或视图。

举个例子,当用户点击一个按钮来修改联系人信息时,按钮(视图组件)会触发一个事件,该事件由一个事件监听器(控制器组件)捕获并处理。监听器内部会调用模型组件的方法来更新数据,然后可能会触发视图组件的更新以反映出数据的改变。

public class ContactController {
    private ContactModel model;
    private ContactView view;
    public ContactController(ContactModel model, ContactView view) {
        this.model = model;
        this.view = view;
        // 注册事件监听器
        this.view.setContactChangedListener(this::updateModel);
    }

    private void updateModel(Contact contact) {
        // 更新模型中的数据
        model.updateContactInfo(contact);
        // 触发视图更新
        view.updateView();
    }
}

上面的代码例子展示了一个简单的MVC实现,其中 ContactController 充当控制器的角色,它监听视图的变化,并更新模型中的数据,反之亦然。这种模式提高了代码的可维护性和模块的独立性。

4.2 MVC模式的应用实践

4.2.1 实现复杂用户界面的策略

在复杂用户界面的实现中,MVC模式能够帮助开发者组织代码,并简化维护和升级过程。以下是几点使用MVC实现复杂用户界面的策略:

  • 分层处理 :对于复杂的界面,可以将视图拆分成多个子视图,每个子视图对应一个或多个控制器。这种方式有助于分摊复杂度,让每个部分更容易理解和维护。

  • 组件化 :使用Swing组件库提供的丰富组件来构建用户界面。例如,使用JTabbedPane创建选项卡式的视图,或使用JTable显示表格数据。

  • 面向接口编程 :定义清晰的模型、视图和控制器接口。这样不仅可以降低不同组件间的耦合度,还可以提高代码的可测试性。

  • 持续集成和测试 :在开发过程中,持续地集成和测试模型、视图和控制器的各个部分,确保每个组件的改动不会影响到其他组件的正常功能。

4.2.2 MVC模式下的数据同步与更新

MVC模式下的数据同步是指确保数据在模型、视图和控制器之间保持一致性。更新则是指当模型中的数据发生变化时,视图应该相应地更新以反映这些变化。

实现数据同步和更新有以下几种策略:

  • 观察者模式 :在MVC模式中,通常使用观察者模式来维护数据的一致性。模型作为被观察者,视图作为观察者。当模型数据发生变化时,通知所有观察者进行更新。

  • 属性变化监听 :Swing框架提供了 PropertyChangeListener 接口,当模型中的属性发生变化时,可以通过此接口来触发视图的更新。

  • 事件驱动更新 :视图在响应用户的交互动作后,通过控制器间接或直接修改模型,然后触发模型的事件,通知视图进行更新。

public class ContactModel {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String newName) {
        String oldName = this.name;
        this.name = newName;
        // 通知观察者名字已更改
        firePropertyChange("name", oldName, newName);
    }
    // 添加属性监听器
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        // 代码省略...
    }
}

在上述代码中, ContactModel 类有一个 name 属性,当这个属性被修改时,会通过 firePropertyChange 方法通知所有注册的属性监听器,从而更新视图。

通过这些策略和实践,MVC模式可以有效地支持复杂用户界面的构建,并确保应用的响应性和一致性。

5. Swing高级主题与自定义绘图

5.1 高级组件的使用

5.1.1 JTabbedPane的使用技巧

JTabbedPane 是Swing中用于管理多个面板的组件,每个面板可以通过标签页的方式进行切换访问。在实际应用中, JTabbedPane 不仅可以放置在窗口内部,也可以被用于对话框和应用程序的多个区域。

import javax.swing.*;

public class TabbedPaneExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("JTabbedPane Example");
        JTabbedPane tabbedPane = new JTabbedPane();

        tabbedPane.addTab("Tab 1", new JPanel());
        tabbedPane.addTab("Tab 2", new JPanel());

        frame.add(tabbedPane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

在上面的代码中,我们创建了一个包含两个标签页的 JTabbedPane 。一个使用技巧是,通过 setTabPlacement() 方法设置标签页的位置(顶部、底部、左侧、右侧),通过 setTabLayoutPolicy() 方法控制标签页的布局策略。

5.1.2 JOptionPane的定制与扩展

JOptionPane 是用于快速生成标准对话框的工具类,它提供了一套简便的API来创建模态对话框、消息框、输入框等。虽然 JOptionPane 本身提供了基本的定制方法,但它也可以被进一步扩展以满足特定的界面需求。

import javax.swing.*;

public class CustomDialogExample {
    public static void main(String[] args) {
        Object[] possibilities = {"Yes", "No", "Maybe"};
        int n = JOptionPane.showOptionDialog(null,
                "Do you like Swing?",
                "Question",
                JOptionPane.YES_NO_CANCEL_OPTION,
                JOptionPane.QUESTION_MESSAGE,
                null,
                possibilities,
                possibilities[0]);
        switch (n) {
            case JOptionPane.YES_OPTION:
                System.out.println("Yes");
                break;
            case JOptionPane.NO_OPTION:
                System.out.println("No");
                break;
            case JOptionPane.CANCEL_OPTION:
                System.out.println("Cancel");
                break;
            case JOptionPane.CLOSE_OPTION:
                System.out.println("Close");
                break;
            default:
                System.out.println("UnKnown");
        }
    }
}

我们可以通过提供一个 JComponent 对象来定制对话框的内容,或者通过 setOptions() 方法来扩展选项按钮。

5.1.3 文件选择、表格和树形视图组件的深入应用

文件选择、表格和树形视图是Swing中常用的复杂组件。这些组件具有丰富的API,支持高度定制和事件处理,可以实现复杂的用户界面交互。

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class AdvancedComponentsExample {
    public static void main(String[] args) {
        // 文件选择
        JFileChooser fileChooser = new JFileChooser();
        int returnValue = fileChooser.showOpenDialog(null);
        if (returnValue == JFileChooser.APPROVE_OPTION) {
            System.out.println("Selected file: " + fileChooser.getSelectedFile().getName());
        }

        // 表格
        JTable table = new JTable(new Object[][]{{"Row1 Col1", "Row1 Col2"}, {"Row2 Col1", "Row2 Col2"}}, new String[]{"Column 1", "Column 2"});
        JScrollPane scrollPane = new JScrollPane(table);

        // 树形视图
        JTree tree = new JTree();
        JScrollPane treeView = new JScrollPane(tree);

        // 显示表格和树形视图
        JFrame frame = new JFrame();
        frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
        frame.add(scrollPane);
        frame.add(treeView);
        frame.pack();
        frame.setVisible(true);
    }
}

5.2 国际化与本地化的实现

5.2.1 资源包的创建与管理

国际化(Internationalization)和本地化(Localization)是软件开发中非常重要的两个方面。资源包是实现国际化和本地化的一种有效方式,它们允许我们为不同的语言环境提供不同的文本资源。

资源包以 ResourceBundle 类的形式存在,通常是 .properties 文件,每种语言一个文件。Java会根据用户的语言环境来加载相应的资源包。

// MyResources.properties (默认语言资源)
hello=Hello World!

// MyResources_fr.properties (法语资源)
hello=Bonjour le monde!

// Java代码使用资源包
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;

public class InternationalizationExample {
    public static void main(String[] args) {
        // 设置默认区域设置为法国
        Locale.setDefault(new Locale("fr", "FR"));
        ResourceBundle messages = ResourceBundle.getBundle("MyResources");
        String helloMessage = messages.getString("hello");
        System.out.println(helloMessage);
    }
}

5.2.2 国际化应用的示例与技巧

一个良好的国际化实践是将所有可本地化的字符串抽离到资源包中,并通过键值对的方式进行访问。这样,在添加新的语言支持时,只需添加相应的 .properties 文件,而不需要修改代码。

// 示例:使用资源包的消息格式化
MessageFormat messageFormat = new MessageFormat("");
messageFormat.setLocale(new Locale("fr", "FR"));
messageFormat.applyPattern(messages.getString("greeting"));
String greeting = messageFormat.format(new Object[]{"John"});
System.out.println(greeting);

技巧包括使用 ResourceBundle.Control 来定制资源加载行为,利用 PropertyResourceBundle ListResourceBundle 来组织资源包,以及使用 ResourceBundle.Control getFallbackLocale 方法处理资源包不存在的情况。

5.3 SwingWorker与MDI应用

5.3.1 SwingWorker的原理与优势

SwingWorker 是Java Swing中用于简化长时间运行任务处理的工具类。它允许在后台线程上执行任务,同时提供了一种在Swing事件调度线程(EDT)上更新GUI的机制。

SwingWorker 的核心优势在于它能够有效地将任务的执行与UI的更新解耦,避免了在GUI线程中进行长时间操作导致的界面冻结问题。

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

public class SwingWorkerExample {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("SwingWorker Example");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JButton startButton = new JButton("Start Long Running Task");
            frame.add(startButton);
            startButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    MySwingWorker worker = new MySwingWorker();
                    worker.execute();
                }
            });
            frame.setSize(300, 200);
            frame.setVisible(true);
        });
    }

    private static class MySwingWorker extends SwingWorker<Void, Void> {
        @Override
        protected Void doInBackground() throws Exception {
            for (int i = 1; i <= 10; i++) {
                Thread.sleep(1000);
                publish(i);
            }
            return null;
        }

        @Override
        protected void process(java.util.List<Void> chunks) {
            // 更新进度条
        }

        @Override
        protected void done() {
            // 任务完成后的处理
        }
    }
}

5.3.2 多文档界面(MDI)的设计与实现

多文档界面(Multiple Document Interface,MDI)允许在同一应用程序窗口内打开和管理多个文档窗口。Swing提供了 JDesktopPane JInternalFrame 组件来实现MDI应用。

import javax.swing.*;
import java.awt.*;

public class MDIApplicationExample {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("MDI Example");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(600, 400);
            JDesktopPane desktop = new JDesktopPane();
            frame.add(desktop);
            JInternalFrame internalFrame = new JInternalFrame("Document", true, true, true, true);
            internalFrame.setSize(300, 200);
            desktop.add(internalFrame);
            internalFrame.setVisible(true);
            frame.setVisible(true);
        });
    }
}

5.4 自定义绘图与特效

5.4.1 绘图API的基础使用

Swing 提供了强大的绘图 API,允许开发者自定义组件的外观和行为。基础的绘图操作包括 Graphics 类的 drawLine , drawRect , drawOval , drawString 等方法。

import javax.swing.*;
import java.awt.*;

public class CustomDrawingExample extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.BLUE);
        g.drawRect(10, 10, 100, 100); // 绘制一个矩形
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Custom Drawing Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new CustomDrawingExample());
        frame.setSize(200, 200);
        frame.setVisible(true);
    }
}

5.4.2 创造性地应用绘图特效

为了创造更具吸引力的用户界面,可以利用Java 2D API扩展绘图功能。Java 2D API提供了对抗锯齿、透明度、颜色转换等高级绘图技术的支持。

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;

public class AdvancedDrawingExample extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();

        // 抗锯齿设置
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 绘制一个渐变色圆形
        GradientPaint paint = new GradientPaint(0, 0, Color.RED, 100, 100, Color.BLUE);
        g2d.setPaint(paint);
        g2d.fill(new Ellipse2D.Double(10, 10, 100, 100));

        g2d.dispose();
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Advanced Drawing Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new AdvancedDrawingExample());
        frame.setSize(200, 200);
        frame.setVisible(true);
    }
}

使用这些特效可以显著提高应用程序的视觉吸引力,增强用户体验。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Swing是Java的一个图形用户界面工具包,属于Java Foundation Classes(JFC)。它提供了丰富的组件库,支持事件驱动编程和MVC设计模式,适用于构建功能强大的桌面应用程序。王鹏的源码分享包括了Swing布局、组件使用、事件处理、菜单栏和快捷键创建、键盘和鼠标事件处理以及国际化等方面的案例详解。深入学习Swing还包括了解SwingWorker、MDI应用、自定义绘图与特效等高级主题。通过实际案例学习,开发者可以掌握Swing组件和机制,提升编程技能,构建高质量的桌面应用。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值