Java-GUI 编程之 Swing
Swing概述
实际使用 Java 开发图形界面程序时 ,很少使用 AWT 组件,绝大部分时候都是用 Swing 组件开发的 。 Swing是由100%纯 Java实现的,不再依赖于本地平台的 GUI, 因此可以在所有平台上都保持相同的界面外观。独立于本地平台的Swing组件被称为轻量级组件;而依赖于本地平台的 AWT 组件被称为重量级组件。
由于 Swing 的所有组件完全采用 Java 实现,不再调用本地平台的 GUI,所以导致 Swing 图形界面的显示速度要比 AWT 图形界面的显示速度慢一些,但相对于快速发展的硬件设施而言,这种微小的速度差别无妨大碍。
使用Swing的优势:
Swing 组件不再依赖于本地平台的 GUI,无须采用各种平台的 GUI 交集 ,因此 Swing 提供了大量图形界面组件 , 远远超出了 AWT 所提供的图形界面组件集。
Swing 组件不再依赖于本地平台 GUI ,因此不会产生与平台 相关的 bug 。
Swing 组件在各种平台上运行时可以保证具有相同的图形界面外观。
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 个额外的功能 :
可以为 Swing 组件设置提示信息。使用 setToolTipText()方法,为组件设置对用户有帮助的提示信息 。
很多 Swing 组件如按钮、标签、菜单项等,除使用文字外,还可以使用图标修饰自己。为了允许在 Swing 组件中使用图标, Swing为Icon 接口提供了 一个实现类: Imagelcon ,该实现类代表一个图像图标。
支持插拔式的外观风格。每个 JComponent 对象都有一个相应的 ComponentUI 对象,为它完成所有的绘画、事件处理、决定尺寸大小等工作。 ComponentUI 对象依赖当前使用的 PLAF , 使用 UIManager.setLookAndFeel()方法可以改变图形界面的外观风格 。
支持设置边框。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的更多相关文章
- Java并发编程之CAS
CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...
- Java网络编程之TCP、UDP
Java网络编程之TCP.UDP 2014-11-25 15:23 513人阅读 评论(0) 收藏 举报 分类: java基础及多线程(28) 版权声明:本文为博主原创文章,未经博主允许不得转载. ...
- Java网络编程之UDP
Java网络编程之UDP 一.C/S架构中UDP网络通信流程 ①创建DatagramSocket与DatagramPacket对象 ②建立发送端,接收端 ③建立数据包 ④调用Socket的发送.接收方 ...
- Java网络编程之URLConnection
Java网络编程之URLConnecton 一.URLConnection简介 URLConnection是一个抽象类,表示指向URL指定资源的活动连接.URLConnection有两个不同但相关的用 ...
- Java网络编程之URL和URI
Java网络编程之URL与URI 一.URL与URI简介 URI = Universal Resource Identifier 统一资源标志符 URL = Universal Resource Lo ...
- Java网络编程之InetAddress浅析
Java网络编程之InetAddress浅析 一.InetAddress综述 IP地址是IP使用的32位(IPv4)或者128位(IPv6)位无符号数字,它是传输层协议TCP,UDP的基础.InetA ...
- Java高性能编程之CAS与ABA及解决方法
Java高性能编程之CAS与ABA及解决方法 前言 如果喜欢暗色调的界面或者想换换界面,可以看看我在个人博客发布的 Java高性能编程之CAS与ABA及解决方法. CAS概念 CAS,全称Compar ...
- Java并发编程之CAS第一篇-什么是CAS
Java并发编程之CAS第一篇-什么是CAS 通过前面几篇的学习,我们对并发编程两个高频知识点了解了其中的一个—volatitl.从这一篇文章开始,我们将要学习另一个知识点—CAS.本篇是<凯哥 ...
- Java并发编程之CAS二源码追根溯源
Java并发编程之CAS二源码追根溯源 在上一篇文章中,我们知道了什么是CAS以及CAS的执行流程,在本篇文章中,我们将跟着源码一步一步的查看CAS最底层实现原理. 本篇是<凯哥(凯哥Java: ...
- Java并发编程之CAS第三篇-CAS的缺点及解决办法
Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...
随机推荐
- struts2学习一:hello struts2及struts2环境配置中遇到的问题
17年下半年的时候简单学了下strus2,好吧,现在已经全忘了,idea也是刚开始用,本来想按教程写个hello struts2,结果,出了以下系列问题. pre:step1-5是我按照百度的教程搭的 ...
- 学习FastDfs(三)
FASTDFS是什么 FastDFS是由国人余庆所开发,其项目地址:https://github.com/happyfish100 FastDFS是一个轻量级的开源分布式文件系统,主要解决了大容量的文 ...
- 学习zabbix(一)
一.zabbix监控简介 server: 通过收集snmp和agent发送的数据,写入数据库(MySQL,ORACLE),再通过 php+apache 在 web 前端展示. agent:主机通过安装 ...
- 三、原理图生成网表并导入PCB放置元件
1.生成网表 2.成功标志 3.新建PCB文件 4.导入网表至PCB 5.导入网表成功标志 6.创建.psm文件(绘制的封装格式为.dra文件,在PCB里面要以.psm的文件存在) 将丝印做成封装需 ...
- 让弹幕给 PPD 生个孩子
怎样才能跑起来我写的弹幕程序 资源下载 申请野狗后端云账号注册 创建应用: 复制appId到index.html的 var ref = new Wilddog("https://<ap ...
- H5复制粘贴双端适配的解决方案(终极版)
前言 最终适配所有机型的方案基于clipboardjs官网https://clipboardjs.com/ 这个库由几个不同的CDN提供商托管.选择你最喜欢的:) jsDelivr <scrip ...
- PAT B1091 N-自守数
输入样例: 3 92 5 233 输出样例: 3 25392 1 25 No '解题思路:判断的时候将结果转换成字符串,判断后面几位数字和输入数字是否相同,掉进了N是从1到10的坑,而不是1到9 ...
- Python入门-import导入模块功能
1.啥是模块 模块(module):用来实现或者多个功能的Python代码,(包含变量.函数.类),本质就是*.py后缀文件. 包(package):定义了一个由模块和子包组成的Python应用程序执 ...
- 【转】shim.ChaincodeStubInterface用法
作为记录 shim.ChaincodeStubInterface用法
- spring配置数据源(加载properties文件)
1.在spring中引入properties配置文件需要引入context的命名空间和真实地址 2.然后加载文件 需要注意的是这是采用的是set注入方式,所以name属性值必须是连接池set方法名去掉 ...