Swing概述

 实际使用 Java 开发图形界面程序时 ,很少使用 AWT 组件,绝大部分时候都是用 Swing 组件开发的 。 Swing是由100%纯 Java实现的,不再依赖于本地平台的 GUI, 因此可以在所有平台上都保持相同的界面外观。独立于本地平台的Swing组件被称为轻量级组件;而依赖于本地平台的 AWT 组件被称为重量级组件

 由于 Swing 的所有组件完全采用 Java 实现,不再调用本地平台的 GUI,所以导致 Swing 图形界面的显示速度要比 AWT 图形界面的显示速度慢一些,但相对于快速发展的硬件设施而言,这种微小的速度差别无妨大碍。

使用Swing的优势:

  1. Swing 组件不再依赖于本地平台的 GUI,无须采用各种平台的 GUI 交集 ,因此 Swing 提供了大量图形界面组件 , 远远超出了 AWT 所提供的图形界面组件集。

  2. Swing 组件不再依赖于本地平台 GUI ,因此不会产生与平台 相关的 bug 。

  3. Swing 组件在各种平台上运行时可以保证具有相同的图形界面外观。

  4. Swing 提供的这些优势,让 Java 图形界面程序真正实现了 " Write Once, Run Anywhere" 的 目标。

Swing的特征:

1.Swing 组件采用 MVC(Model-View-Controller, 即模型一视图一控制器)设计模式:

  • 模型(Model): 用于维护组件的各种状态;
  • 视图(View): 是组件的可视化表现;
  • 控制器(Controller):用于控制对于各种事件、组件做出响应 。

 当模型发生改变时,它会通知所有依赖它的视图,视图会根据模型数据来更新自己。Swing使用UI代理来包装视图和控制器, 还有一个模型对象来维护该组件的状态。例如,按钮JButton有一个维护其状态信息的模型ButtonModel对象 。 Swing组件的模型是自动设置的,因此一般都使用JButton,而无须关心ButtonModel对象。

2.Swing在不同的平台上表现一致,并且有能力提供本地平台不支持的显示外观 。由于 Swing采用 MVC 模式来维护各组件,所以 当组件的外观被改变时,对组件的状态信息(由模型维护)没有任何影响 。因 此,Swing可以使用插拔式外观感觉 (Pluggable Look And Feel, PLAF)来控制组件外观,使得 Swing图形界面在同一个平台上运行时能拥有不同的外观,用户可以选择自己喜欢的外观 。相比之下,在 AWT 图形界面中,由于控制组件外观的对等类与具体平台相关 ,因此 AWT 组件总是具有与本地平台相同的外观 。

Swing组件层次

Swing组件继承体系图:

​ 大部分Swing 组件都是 JComponent抽象类的直接或间接子类(并不是全部的 Swing 组件),JComponent 类定义了所有子类组件的通用方法 ,JComponent 类是 AWT 里 java.awt. Container 类的子类 ,这也是 AWT 和 Swing 的联系之一。 绝大部分 Swing 组件类继承了 Container类,所以Swing 组件都可作为 容器使用 ( JFrame继承了Frame 类)。

Swing组件和AWT组件的对应关系:

​ 大部分情况下,只需要在AWT组件的名称前面加个J,就可以得到其对应的Swing组件名称,但有几个例外:

​ 1. JComboBox: 对应于 AWT 里的 Choice 组件,但比 Choice 组件功能更丰富 。

2. JFileChooser: 对应于 AWT 里的 FileDialog 组件 。

3. JScrollBar: 对应于 AWT 里的 Scrollbar 组件,注意两个组件类名中 b 字母的大小写差别。

4. JCheckBox : 对应于 AWT 里的 Checkbox 组件, 注意两个组件类名中 b 字母的大小 写差别 。

5. JCheckBoxMenultem: 对应于 AWT 里的 CheckboxMenuItem 组件,注意两个组件类名中 b字母的大小写差别。

Swing组件按照功能来分类:

AWT组件的Swing实现

​ Swing 为除 Canvas 之外的所有 AWT 组件提供了相应的实现,Swing 组件比 AWT 组件的功能更加强大。相对于 AWT 组件, Swing 组件具有如下 4 个额外的功能 :

  1. 可以为 Swing 组件设置提示信息。使用 setToolTipText()方法,为组件设置对用户有帮助的提示信息 。

  2. 很多 Swing 组件如按钮、标签、菜单项等,除使用文字外,还可以使用图标修饰自己。为了允许在 Swing 组件中使用图标, Swing为Icon 接口提供了 一个实现类: Imagelcon ,该实现类代表一个图像图标。

  3. 支持插拔式的外观风格。每个 JComponent 对象都有一个相应的 ComponentUI 对象,为它完成所有的绘画、事件处理、决定尺寸大小等工作。 ComponentUI 对象依赖当前使用的 PLAF , 使用 UIManager.setLookAndFeel()方法可以改变图形界面的外观风格 。

  4. 支持设置边框。Swing 组件可以设置一个或多个边框。 Swing 中提供了各式各样的边框供用户边 用,也能建立组合边框或自己设计边框。 一种空白边框可以用于增大组件,同时协助布局管理器对容器中的组件进行合理的布局。

​ 每个 Swing 组件都有一个对应的UI 类,例如 JButton组件就有一个对应的 ButtonUI 类来作为UI代理 。每个 Swing组件的UI代理的类名总是将该 Swing 组件类名的 J 去掉,然后在后面添加 UI 后缀 。 UI代理类通常是一个抽象基类 , 不同的 PLAF 会有不同的UI代理实现类 。 Swing 类库中包含了几套UI代理,分别放在不同的包下, 每套UI代理都几乎包含了所有 Swing组件的 ComponentUI实现,每套这样的实现都被称为一种PLAF 实现 。以 JButton 为例,其 UI 代理的继承层次下图:

​ 如果需要改变程序的外观风格, 则可以使用如下代码:

//容器:
JFrame jf = new JFrame(); try { //设置外观风格
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); //刷新jf容器及其内部组件的外观
SwingUtilities.updateComponentTreeUI(jf);
} catch (Exception e) {
e.printStackTrace();
}

案例:

​ 使用Swing组件,实现下图中的界面效果:

演示代码:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent; public class SwingComponentDemo { JFrame f = new JFrame("测试swing基本组件"); // 定义一个按钮,并为其指定图标
JButton ok = new JButton("确定",new ImageIcon("ok.png")); // 定义一个单选按钮,初始处于选中的状态
JRadioButton male = new JRadioButton("男", true);
// 定义一个单选按钮,初始处于选中状态
JRadioButton female = new JRadioButton("女", false); // 定义一个ButtonGroup,把male和female组合起来,实现单选
ButtonGroup bg = new ButtonGroup(); // 定义一个复选框,初始处于没有选中状态
JCheckBox married = new JCheckBox("是否已婚?", false); // 定义一个数组存储颜色
String[] colors = { "红色", "绿色 ", "蓝色 " }; // 定义一个下拉选择框,展示颜色
JComboBox<String> colorChooser = new JComboBox<String>(colors); // 定一个列表框,展示颜色
JList<String> colorList = new JList<String>(colors); // 定义一个8行20列的多行文本域
JTextArea ta = new JTextArea(8, 20); // 定义一个40列的单行文本域
JTextField name = new JTextField(40); // 定义菜单条
JMenuBar mb = new JMenuBar(); // 定义菜单
JMenu file = new JMenu("文件");
JMenu edit = new JMenu("编辑"); // 创建菜单项,并指定图标
JMenuItem newItem = new JMenuItem("新建", new ImageIcon("new.png"));
JMenuItem saveItem = new JMenuItem("保存", new ImageIcon("save.png"));
JMenuItem exitItem = new JMenuItem("退出", new ImageIcon("exit.png")); JCheckBoxMenuItem autoWrap = new JCheckBoxMenuItem("自动换行");
JMenuItem copyItem = new JMenuItem("复制", new ImageIcon("copy.png"));
JMenuItem pasteItem = new JMenuItem("粘贴", new ImageIcon("paste.png")); // 定义二级菜单,将来会添加到编辑中
JMenu format = new JMenu("格式");
JMenuItem commentItem = new JMenuItem("注释");
JMenuItem cancelItem = new JMenuItem("取消注释"); // 定义一个右键菜单,用于设置程序的外观风格
JPopupMenu pop = new JPopupMenu(); // 定义一个ButtongGroup对象,用于组合风格按钮,形成单选
ButtonGroup flavorGroup = new ButtonGroup(); // 定义五个单选按钮菜单项,用于设置程序风格
JRadioButtonMenuItem metalItem = new JRadioButtonMenuItem("Metal 风格", true);
JRadioButtonMenuItem nimbusItem = new JRadioButtonMenuItem("Nimbus 风格", true);
JRadioButtonMenuItem windowsItem = new JRadioButtonMenuItem("Windows 风格", true);
JRadioButtonMenuItem classicItem = new JRadioButtonMenuItem("Windows 经典风格", true);
JRadioButtonMenuItem motifItem = new JRadioButtonMenuItem("Motif 风格", true); // 初始化界面
public void init() { // ------------------------组合主区域------------------------
// 创建一个装载文本框和按钮的JPanel
JPanel bottom = new JPanel();
bottom.add(name);
bottom.add(ok); f.add(bottom, BorderLayout.SOUTH); // 创建一个装载下拉选择框、三个JChekBox的JPanel
JPanel checkPanel = new JPanel();
checkPanel.add(colorChooser);
bg.add(male);
bg.add(female); checkPanel.add(male);
checkPanel.add(female);
checkPanel.add(married); // 创建一个垂直排列的Box,装载checkPanel和多行文本域
Box topLeft = Box.createVerticalBox(); // 使用JScrollPane作为普通组件的JViewPort
JScrollPane taJsp = new JScrollPane(ta);
topLeft.add(taJsp);
topLeft.add(checkPanel); // 创建一个水平排列的Box,装载topLeft和colorList
Box top = Box.createHorizontalBox();
top.add(topLeft);
top.add(colorList); // 将top Box 添加到窗口的中间
f.add(top); // ---------------------------组合菜单条----------------------------------------------
// 为newItem添加快捷键 ctrl+N
newItem.setAccelerator(KeyStroke.getKeyStroke('N', InputEvent.CTRL_MASK));
newItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {
ta.append("用户点击了“新建”菜单\n");
}
}); // 为file添加菜单项
file.add(newItem);
file.add(saveItem);
file.add(exitItem); // 为edit添加菜单项
edit.add(autoWrap);
edit.addSeparator();
edit.add(copyItem);
edit.add(pasteItem);
// 为commentItem添加提示信息
commentItem.setToolTipText("将程序代码注释起来"); // 为format菜单添加菜单项
format.add(commentItem);
format.add(cancelItem); // 给edit添加一个分隔符
edit.addSeparator(); // 把format添加到edit中形成二级菜单
edit.add(format); // 把edit file 添加到菜单条中
mb.add(file);
mb.add(edit); // 把菜单条设置给窗口
f.setJMenuBar(mb); // ------------------------组合右键菜单----------------------------- flavorGroup.add(metalItem);
flavorGroup.add(nimbusItem);
flavorGroup.add(windowsItem);
flavorGroup.add(classicItem);
flavorGroup.add(motifItem); // 给5个风格菜单创建事件监听器
ActionListener flavorLister = new ActionListener() {
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
try {
changeFlavor(command);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}; // 为5个风格菜单项注册监听器
metalItem.addActionListener(flavorLister);
nimbusItem.addActionListener(flavorLister);
windowsItem.addActionListener(flavorLister);
classicItem.addActionListener(flavorLister);
motifItem.addActionListener(flavorLister); pop.add(metalItem);
pop.add(nimbusItem);
pop.add(windowsItem);
pop.add(classicItem);
pop.add(motifItem); // 调用ta组件的setComponentPopupMenu即可设置右键菜单,无需使用事件
ta.setComponentPopupMenu(pop); // 设置关闭窗口时推出程序
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置jFrame最佳大小并可见
f.pack();
f.setVisible(true); } // 定义一个方法,用于改变界面风格
private void changeFlavor(String command) throws Exception {
switch (command) {
case "Metal 风格":
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
break;
case "Nimbus 风格":
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
break;
case "Windows 风格":
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
break;
case "Windows 经典风格":
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");
break;
case "Motif 风格":
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
break;
} // 更新f窗口内顶级容器以及所有组件的UI
SwingUtilities.updateComponentTreeUI(f.getContentPane());
// 更新mb菜单条及每部所有组件UI
SwingUtilities.updateComponentTreeUI(mb);
// 更新右键菜单及内部所有菜单项的UI
SwingUtilities.updateComponentTreeUI(pop);
} public static void main(String[] args) {
new SwingComponentDemo().init();
} }

注意细节:

1.Swing菜单项指定快捷键时必须通过组件名.setAccelerator(keyStroke.getKeyStroke("大写字母",InputEvent.CTRL_MASK))方法来设置,其中KeyStroke代表一次击键动作,可以直接通过按键对应字母来指定该击键动作 。

2.更新JFrame的风格时,调用了 SwingUtilities.updateComponentTreeUI(f.getContentPane());这是因为如果直接更新 JFrame 本身 ,将会导致 JFrame 也被更新, JFrame 是一个特殊的容器 , JFrame 依然部分依赖于本地平台的图形组件 。如果强制 JFrame 更新,则有可能导致该窗口失去标题栏和边框 。

3.给组件设置右键菜单,不需要使用监听器,只需要调用setComponentPopupMenu()方法即可,更简单。

4.关闭JFrame窗口,也无需监听器,只需要调用setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)方法即可,更简单。

5.如果需要让某个组件支持滚动条,只需要把该组件放入到JScrollPane中,然后使用JScrollPane即可。

公众号文章地址:

https://mp.weixin.qq.com/s/2ZqSWTvpkz1k1Y-Ztp5a4g

https://mp.weixin.qq.com/s/0S3tK1-ENMVCfECmPck-_w

https://mp.weixin.qq.com/s/CZySRASKmWpRPoJoRfhmYw

https://mp.weixin.qq.com/s/oB_LZY2BHAcJt7WykqdXww

Java-GUI 编程之 Swing的更多相关文章

  1. Java并发编程之CAS

    CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...

  2. Java网络编程之TCP、UDP

    Java网络编程之TCP.UDP 2014-11-25 15:23 513人阅读 评论(0) 收藏 举报 分类: java基础及多线程(28) 版权声明:本文为博主原创文章,未经博主允许不得转载.   ...

  3. Java网络编程之UDP

    Java网络编程之UDP 一.C/S架构中UDP网络通信流程 ①创建DatagramSocket与DatagramPacket对象 ②建立发送端,接收端 ③建立数据包 ④调用Socket的发送.接收方 ...

  4. Java网络编程之URLConnection

    Java网络编程之URLConnecton 一.URLConnection简介 URLConnection是一个抽象类,表示指向URL指定资源的活动连接.URLConnection有两个不同但相关的用 ...

  5. Java网络编程之URL和URI

    Java网络编程之URL与URI 一.URL与URI简介 URI = Universal Resource Identifier 统一资源标志符 URL = Universal Resource Lo ...

  6. Java网络编程之InetAddress浅析

    Java网络编程之InetAddress浅析 一.InetAddress综述 IP地址是IP使用的32位(IPv4)或者128位(IPv6)位无符号数字,它是传输层协议TCP,UDP的基础.InetA ...

  7. Java高性能编程之CAS与ABA及解决方法

    Java高性能编程之CAS与ABA及解决方法 前言 如果喜欢暗色调的界面或者想换换界面,可以看看我在个人博客发布的 Java高性能编程之CAS与ABA及解决方法. CAS概念 CAS,全称Compar ...

  8. Java并发编程之CAS第一篇-什么是CAS

    Java并发编程之CAS第一篇-什么是CAS 通过前面几篇的学习,我们对并发编程两个高频知识点了解了其中的一个—volatitl.从这一篇文章开始,我们将要学习另一个知识点—CAS.本篇是<凯哥 ...

  9. Java并发编程之CAS二源码追根溯源

    Java并发编程之CAS二源码追根溯源 在上一篇文章中,我们知道了什么是CAS以及CAS的执行流程,在本篇文章中,我们将跟着源码一步一步的查看CAS最底层实现原理. 本篇是<凯哥(凯哥Java: ...

  10. Java并发编程之CAS第三篇-CAS的缺点及解决办法

    Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...

随机推荐

  1. 一个tomcat部署两个springboot服务时启动JMX报错

    一.问题来源 今天在部署开发好的组件的时候,发现无法启动,检查启动日志,报如下错误: 2022-03-17T10:39:41.823+08:00 ERROR vediomanage.vediomana ...

  2. 生命周期内create和mounted的区别?

    created: 在模板渲染成html前调用,即通常初始化某些数据,然后再渲染成视图. mounted: 在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作 ...

  3. java-规约-集合

    /** * 1 * @hashCode&equals的处理: * 1-只要覆写了equals,必须复写hashCode. * 2-因为Set存储的是不重复的对象,依据hashCode和equa ...

  4. Linux下离线安装docker与fastDFS

    一.Linux下离线安装Docker 基础环境 1.操作系统:CentOS 7 2.Docker版本:docker-19.03.9.tgz 官方下载地址(打不开可能需要科学-上网) 3.官方参考文档: ...

  5. 在 Spring 框架中如何更有效地使用 JDBC?

    使用 SpringJDBC 框架,资源管理和错误处理的代价都会被减轻.所以开发者只 需写 statements 和 queries 从数据存取数据,JDBC 也可以在 Spring 框架提供 的模板类 ...

  6. 为什么需要域驱动设计DDD?

    我们需要 DDD 的因素 – 微服务面试问题

  7. Linux编程 | 使用 make

    目录 简单的 makefile 文件 常规的 makefile 文件 常用参数 make 内置规则 后缀和模式规则 make 管理函数库 在Linux 环境中,make 是一个非常重要的编译命令.不管 ...

  8. 03. Pandas数据结构

    03. Pandas数据结构 Series DataFrame 从DataFrame中查询出Series 1. Series Series是一种类似于一维数组的对象,它由一组数据(不同数据类型)以及一 ...

  9. React-简单通用的抛物线动画

    一个简单通用的 React 抛物线动画demo Usage import { parabola } from "./parabola" ... onAnimate = () =&g ...

  10. 微信小程序上拉加载:onReachBottom详解+设置触发距离

    前端经常遇到上拉加载更多的需求,一般还涉及到翻页.小程序里已经给了下拉到底的触发方法onReachBottom(),这里记录下怎样使用这个方法实现下拉加载更多,有需要的直接看代码,有详细注释: 1.首 ...