第12章Swing编程
Swing它采用100%java实现 不在依赖本地平台,所有平台都可以保持相同的运行效果,对跨平台支持比较出色 实现了MVC设计模式也称为Model-Delegate(模式-代理)
12.1 Swing概况
独立于本地平台的Swing(速度慢点)组件被称为轻量级组件,而依赖本地平台的AWT组件被称为重量级组件
12.2 Swing 基本组件的用法
12.2.1 Swing 组件层次
大部分Swing组件都是JComponent抽象类的直接或者间接子类,JComponent类继承了java.atw.Containter类,所以Swing组件类可作为容器使用
Swing中包含了4个组件直接继承了AWT组件,而不是从JComponent派生,JFrame
JWindows
JDialog JApplet 他们并不是轻量级组件,而是重量级组件(需要委托给GUI组件的平台)
Swing组件按功能来分,又可以分为几类
1. 顶层容器 :JFrame JWindows JDialog JApplet
2. 中间容器 :JPanel JScrollPane JSplitane JTooLBar
3. 特殊容器 : 在用户界面上具有特殊作用的中间容器 如 JInternalFrame JRootPane
4. 基本组件 : 实现人机交互的组件 JButton JMenu
5. 不可编辑信息的显示组件 :向用户显示不可以编辑的组件信息 JLable
6. 可编辑信息的显示组件 : 向用户显示被编辑的格式化信息的组件 JTable JTextArea
7. 特殊对话框组件 如JColorChooser 和JFileChooser
12.2.2 AWT组件的Swing实现
相对于AWT组件
Swing组件具有如下4个功能
1.可以为Swing组件设置提示信息
2.很多Swing组件如 按钮 标签 菜单等 除了使用文字外,还可以使用图标标示自己
3.支持插拔式的外观风格
4.支持设置边框
AWT菜单对象在创建快捷键时,直接传入KeyShortcut对象为其制定快捷键,但Swing菜单项制定快捷键必须通过setAccelerator(KeyStroke
ks)方法来设定
SwingUtilities 类的updateComponentTreeUI()方法类跟新制定容器的注意的是跟新的是JFrame对象getContentPanel()方法的返回值,而不是直接跟新JFrame
JFrame依然依赖于本地平台的图像组件
JScrollPane对于JTable组件尤其重要,通常需要把JTable放在JScrollPane容器中才可以显示出JTable组件的标题栏
12.2.3位组件设置边框
可以调用JComponent提供的setBorder(Border b)方法为Swing组件设置边框,其中Border是Swing的接口
TitledBorder 和Component
比较独特,其中TitleBorder的作用是为其他边框设计标题,当创建一个TitledBorder对象时,就需要传入一个已经存在的Border对象,因此每创建一个ComponentBorder对象时都需要传入两个Border对象,一个用作组件的内边框,一个用于组件的外边框
Swing组件添加边框的步骤如下
1.使用BorderFactor或者XxxBorder创建XxxBorder实例
2.调用Swing组件的setBorder(Border b)方法为该组件设置边框
12.2.4 Swing组件的双缓存和键盘驱动
Swing 组件还有两个功能
1. 所有的Swing组件默认启用双缓存绘图技术(避免频繁重绘GUI组件时显示闪烁现象)默认开启
2. 所有的Swing组件都提供了简单的键盘驱动
JComponent类提供了getInputMap()
返回一个InputMap对象,该对象用于将KeyStroke对象和名字关联;getActionMap()返回一个ActionMap对象
用于将制定名字和Action关联,从而可以允许用户通过键盘来操作代替鼠标驱动GUI上的Swing组件
(相当于提供快捷键)
12.2.5 使用JToolBar创建工具条
Swing提供了JToolBar来创建工具条,创建JToolBar对象时可以制定如下两个参数
name :该参数为工具条的名称
orientation : 该参数表示工具条的方向
Action接口是ActionListener接口的子接口,处理提供actionPerformed()方法之外,还包含
name 和
icon 不仅可以作为事件监听器使用,还可以转换为按钮或者菜单项
Action本身不是按钮也不是菜单项,只有当把Action对象添加当某些组件(也可以直接使用Action来创建)也就是说 这些容器需要负责完成如下的事
1.创建一个试用与该容器的组件
2.从Action对象的初始化中获得对于的属性来设置组件
3.检查Action对象的初始化 确定它是否是激活状态
4.通过Action对象为对应组件注册事件监听器
12.2.6 使用JFileChooser
JFileChooser用于创建颜色的对话框 该方法提供了两个静态方法
showDialog(Componment c ,Stting title ,Color col)大部分时候时用来让用户选择颜色
createDialog(Component c ,String tilte ,boolean modal ,JColorChoose jc ,ActionListener listerner ,ActionListenenr cann)
JFileChooser的功能与AWT中的FileDialog基本相似,也就是生成“打开文件”,“保存文件”对话框
为了调用JFileChooser来打开一个文件对话框,必须下创建该对话框的实例,JFileChooser提供了多个构造器来创建JFileChooser对象
JFileChooser 调用showXxxDialog()方法来显示文件对话框,
使用JFileChooser来创建文件对话框运行用户选择文件的步骤如下
1. 采用构造器创建一个JFileChooser对象,该JFileChooser对象无需指定parent组件,所有可以在多个组件之间共有JFileChooser对象
2. 调用JFileChooser的一系列可选方法对JFileChooser执行操作
3. 如果让文件对话框实现文件过滤功能,则需要结合FileFilter类来进行文件过滤
4. 如果需要改变文件对话框的视图外观,则可以结合FileView类来改变对话框中文件的视图外观
5. 调用showXxxDialog 方法可以打开文件对话框
6. JFileChooser提供了两个方法来获取用户选择文件或文件集
12.2.7 使用JOptionPane
通过JOptionPane可以非常方便的创建一些简单的对话框,Swing已经为这些对话框添加了相应的组件,无需程序员手动添加组件
JOptionPane提供了4个方法来创建对话框
1. showMessageDialog/showInternalMessageDialog
消息对话框,用户只能点确定(类似js alert)
2. showConfirmDialog/showInternalComfirmDialog
确定对话框 想用户确定某一个问题 用户可以选择yes no canel
等 (类似JS
的 comfirm)
3. showInputDialog/showInternalInputDialog
输入对话框,提示要求输入某些信息,类似于JS的prompt函数 改方法返回用户输入的字符串
4. showOptionDialog/showInternalOptionDialog自定义对话框,可以替代showConfirmDialog所产生的对话框,只是用起来更复杂
JOptionPane产生的所有对话框都是模式的,在用户完成对话框交互前都会一直阻塞当前的线程
12.3 Swing中的特殊容器
Swing提供了一些具有特殊功能的容器,用于创建一些更复杂的用户界面
12.3.1 使用JSplitPane
JSplitPane用于创建一个分割面板,它可以将一个组件(通常是容器)分割成两个部分,并提供一个分割条,用户可以调整两部分的大小
创建分隔板时可以制定一个newContinuousLayout参数,该参数指定分割面板是否支持连续分布(分割线两边组件将不断的调整大小)
12.3.2 使用JTabbedPane
JTabbedPane可以很方便的在窗口上放置多个标签页,每个标签页相当于获得一个与外部容器具有大小相同的组件摆放区,通过这种方式,可以在一个容器里放置更多的组件
如果需要使用JTabbedPane在窗口上创建标签页步骤如下
1.创建一个JTabbedPane对象(构造器包含如下两个参数
tabPlacement 指定标签页放置的位置 tabLayoutPolicy
指定标签页的布局策略 有两种(JTabbedPane.WRAP_TAB_LAYOUT)标题换行 (SCROLL_TAB_LAYOUT)使用滚动条显示)
2.调用JTabbedPane对象的addTab() insertTab()()等方法来增删改查(不要使用add()方法来增加组件
后插入的组件会覆盖之前增加的组件)
3.如果需要某一个标签显示出来则可以调用JTabbedPane的setSelectedIndex()方法来实现
4.程序还可以通过JTabbedPane提供的一系列方法来操作JTabbedPane的相关属性
5.如果程序需要监听用户点击某一个标签,则可以使用监听器来监听JTabbedPane对象
12.3.3使用JLayeredPane JDesktopPane
和JInternalFrame
JLayeredPane是一个代表有层次深度的容器,它允许组件在需要时互相叠加,当向JLayeredPane容器中添加组件时,需要为组件指定一个深度索引,其中层次索引较高的层的组件位于其他层组件之上
向JLayeredPane中添加组件必须要显示的设置该组件的大小和位置 ,否则该组件显示不出来
JDesktopPane 需要和JInternalFrame组合使用,其中JDesktopPane代表了一个虚拟桌面,而JInternalFrame则用于创建内部窗口
创建步骤如下
1. 创建一个JDesktopPane对象,
2. 使用JInternalFrame创建一个内部窗口,创建内部窗口时除了可以穿字符串作为窗口的名字还可以传4个Boolean值
用于表示是否允许改变窗口大小 关闭窗口 最大化窗口 最小化窗口
3. 一旦获得内部窗口之后,该窗口的用法和普通窗口的用法基本一样,一样可以制定该窗口的布局管理器,可以添加组件。。
4. 将该内部窗口以合适的大小合适的位置显示出来(该窗口默认大小是0*0
位于 0,0处于隐藏状态)
5. 将内部窗口添加到 JDesktopPane
容器,在将 JDesktopPane
容器加到其他容器
JDesktopPane 不能独立存在,必须将 JDesktopPane
添加到其他顶级容器中才能正常使用
12.4 Swing简化拖放功能
java 1.4 开始Swing部分组件就提供了默认的拖放支持,除此之外,Swing还提供该了一个非常特殊的类
TransferHandler,它可以直接将某一个组件的指定属性设置为拖放目标(前提该组件具有该属性的setter方法)
12.5 java 7 新增的Swing功能
java 7 提供了重大的更新包括对Swing的更新,对Swing的更新除了前面介绍的Nimbus外观改进了JColorChooser组件外,还有两个重要的跟新
JLayer和创建不规则窗口
12.5.1 使用JLayer装饰组件
JLayer的功能是在指定的组件上额外的添加一个装饰层,开发者可以在这个装饰层上任意绘制,可以指定组件添加任意装饰
JLayer一般总是要和LayerUI一起使用 ,而LAyerUI用于被扩展,扩展时重写它的paint(Graphics
g ,JComponent c)方法
12.5.2 创建透明、不规则状态窗口
java 7 位Frame提供了两个方法
serShape(Shape shape) 设置窗口的形状
serOpacity(float opacity)设置窗口的透明度
12.6 使用JProgressBar ProgressMonitor 和BoundedRangeModel
创建进度条
12.6.1 创建进度条
使用JProgressBar可以非常方便的创建进度条,步骤如下
1.创建一个JProgressBar对象,创建对象时可以指定3个参数,(用于设置进度条的排列方式 进度条的最大和最小值)
2.调用该对象的常用方法设置进度条的普通方法
3.当程序中工作进度完成改变时,调用用于JProgressBar对象的setValue()方法
12.6.2 创建进度对话框
ProgressMonitor的用法和JProgressBar的用法基本相似,只是ProgressMonitor可以直接创建一个进步对话框
ProgressMonitor提供如下构造器
ProgressMonitor(Component parentcom ,Object message , String note ,int mix ,int max)
使用ProgressMonitor创建的对话框包含的进度条是一个非常固定的 程序甚至不能设置该进度条是否包含边框,(总是包含边框)不能设置进度不确定,不能改变进度条的方向(总是水平方向)
12.7 使用JSider和BoundedRangeModel创建滑动条
JSider的用法和JProgressBar的用法非常相似,这一点可以从它们共享同一个Model类看出来 主要区别如下
1.JSlide不是采用填充颜色的方式来表示该组件的当前值,而是采用滑块的位置来表示该组件的当前值
2.JSider允许用户手动改变滑动条的当前值
3.JSider 允许为滑动条指定刻度值,这系列的刻度值可以是连续的数字,也可以是自定义的刻度值,甚至可能是图标
使用JSider的构造器创建滑动条的步骤如下
1.使用JSider的构造器创建一个JSider对象,
2.调用JSider的如下方法来设置滑动条的外观样式
3.如果程序需要在用户拖动滑块时做出相应的处理,则应为JSider对象添加时间监听器
4.将JSider对象添加到其他容器中显示出来
12.8 使用JSpinner
和SpinnerModel
创建微调控制器
JSpinner组件是一个带有两个小箭头的文本框,这个文本框只能接收满足要求的数据,用户既可以通过小箭头调整该微调控制器的值,也可以直接在文本框内输入内容来改变文本框微调控制器的值
通常JSpinner组件经常需要和SprinnerModel结合使用,其中JSpinner控制组件的外观,而SprinnerModel控制该组件的内部状态数据
JSpinner组件的值可以是数值 日期 和List中的值
JSpinner组件还可以是任意系列 只要这个系类可以通过previous()
next() 获得值即可,在这种情况下用户必须自行提供SpinnerModel实现类
12.9 使用JList JComboBox创建列表框
JList 和JComboBox都是极其相似的,他们都有一个列表框,只有JComboBox的列表框需要以下拉方式显示出来
JList JComboBox都可以通过调用setRenderer()方式来改变列表框的表现形式
12.9.1简单列表框
如果仅需要创建一个简单的列表框,则直接使用他们的构造器即可,他们的构造器都可以接收一个对象数组或者元素类型的任意Vector作为参数,这个对象数组或元素类型任意的Vector里的所有元素将被转换为列表框的列表项
步骤
1.使用JList JComboBox的构造器来创建一个列表框对象
2.调用JList JComboBox 的各种方法来设置列表框的外观行为
3.如果有需要监听列表框选项的变化,则可以通过监听器来实现
12.9.2 不强制存储列表项的JListModel
和 JComboBoxModel
Swing的绝大部分组件都实现了MVC的设计模式,其中JListModel
和 JComboBoxModel只负责组件的外观显示,而组件的状态数据维护则有对应的Model负责,JList对应的Model是ListModel接口
12.9.3 强制存储列表项的DefaultListModel和DefaultComboBoxModel
当使用JListModel 和
JComboBoxModel时常常需要动态的增加插入删除列表项
但是JListModel 并没有提供这些类似的方法,实际上对于JList还是很难删除列表项。
所以应该在创建JList时显示使用DefaultListModel作为构造参数
因为DefaultListModel作为JList的Model,它负责维护JList组件的所有列表数据
为什么JComboBox提供了增删改 而
JList没有
因为 直接使用数组 vector 创建JList和JComboBox对应实现类不一样,创建JComboBox的Model是DefaultComboBoxModel,这是一个可变集合类,所有使用数组集合可以直接增删改
但使用数据Vector创建的JList对应的Model分别是JList$1,JList$2
(内部类)
DefaultListModel和DefaultComboBoxModel
是两个强制保存所有列表项的Model类,他们使用Vector来保存所有列表项
12.9.4 使用ListCellRender
改变列表项外观
JList 和JComboBox
都可以支持图标列表,如果创建JList
和JComboBox
传入图标数组,则创建的JList
和JComboBox
列表项就是图标
ListCellRender只是一个接口,它并未强制指定列表项绘制属于那种组件,因此可扩展任何组件来实现ListCellRender接口
12.10 使用 JTree
和TreeModal创建树
树是图形用户界面中使用非常广泛的GUI组件,
一个树只能有一个根节点如果一个树有多个节点,那它就不是树一棵树了,而是多棵树的集合,也被称为森林
12.10.1 创建树
Swing使用JTree对象来代表一棵树,(实际上也可以是森林)JTree树种节点可以使用TreePath来标识,该对象封装了当前节点及所有父节点
节点及所有的父节点才能标识一个节点
一个节点有2种状态
1.展开状态
2.折叠状态
只有当某一个节点的所有父节点(直接的和间接的)都全部展开才能是可见的
如果希望创建一棵树,则直接使用JTree构造器创建JTree对象即可
为了利用根节点来创建JTree,程序需要创建一个TreeNode对象(接口),该接口有一个子接口MutableTreeNode,程序可以通过该接口的实现类DefaultMutableTreeNode来创建树节点并通过add()方法来添加节点之间的父子关系
DefaultMutableTreeNode提供还提供了深度优先遍历和广度优先遍历两个方法
12.10.2 拖到,编辑树节点
JTree生成的树默认是不可编辑的,不可以添加、删除节点,也不可以变换节点,如果想让某一个树变成可编辑状态,则可以调用JTree的setEditable(Boolean
b)改为true即可变成可编辑的树了
JTree处理节点有两种方式
1.一种是根据TreePath
2.另一种是根据节点行号
所有JTree显示的节点都有一个唯一的行号,只有那些被显示出来的节点才有行号,(如果该节点之前被展开 折叠或者修改 那么该节点行号可能发生变化)所以使用TreePath比较稳定
12.10.3 监听节点事件
JTree专门提供了一个TreeSelectionModel对象来保存该JTree选中状态信息,也就是说JTree组件背后隐藏了两个model对象,其中TreeModel用于保存该JTree的所有节点数据,而TreeSelectionModel用于保存该JTree中被选中的信息
程序可以通过getSelectPath 和getSelectPaths()方法来获取被选中的TreePath
实际上这两个方法还是依赖于TreeSelectionModel
12.10.4 使用DefaultTreeCellRenderer改变节点外观
JTree也可也改变树节点的外观,包括改变节点的图标,字体等,甚至可以自由绘制节点的外观,为了改变外观,可以通过树指定自己的CellRenderer来实现,JTree默认使用DefaultTreeCellRenderer来绘制每个节点
该类是JLabel的子类
改变树节点的外观样式 可以有如下三种方式
1.使用DefaultTreeCellRenderer直接改变节点的外观,这种方式可改变整棵树所有节点的字体颜色和图标
2.为JTree指定DefaultTreeCellRenderer的扩展对象作为JTree的节点绘制器,该节点负责为不同的节点使用不同的字体颜色和图标
3.为JTree指定一个实现TreeCellRenderer接口的节点绘制器 该节点可为不同的节点自由绘制任意内容
12.10.5 扩展DefaultTreeCellRenderer改变节点外观
DefaultTreeCellRenderer类实现了TreeCellRenferer接口,给接口里只有一个用于绘制节点内容的方法
getTreeCellRendererComponent(),该方法负责绘制JTree节点
DefaultTreeCellRenderer类继承了JLabel,实现getTreeCellRendererComponent()方法时返回this,返回的是JLabel对象
12.10.6 实现TreeCellRenderer改变外观
程序实现TreeCellRenderer时一样要实现getTreeCellRendererComponent()方法,该方法返回任意类型的组件,该组件将作为JTree节点
程序同样是通过扩展JPanel来实现TreeCellRenferer
12.11 使用JTable和TableModel创建表格
12.11.1 创建表格
使用JTable来创建表格是非常容易的事情,JTable可以把一个二维数据包装成一个表格这个二维数据包可以是二维数组也可以是集合元素为Vector的Vector对象
在默认情况下 JTable的表格数据,表格列表全部都是字符串内容,可以通过特定的TableModel或者自己制定自己的单元格绘制器来实现
通常应该讲JTable对象放在JScrollPane容器由JSrollPane为JTable提供viewPort(不仅可以为JTable增加滚动条,而且可以让JTable的标题显示出来,如果不把JTable放在JScorllPane中
JTable默认不会显示列标题)
12.11.2 TableModel 和监视器
与JList. JTree类似的是,JTable采用TableModel来保存表格中的所有状态数据,与ListModel类似的是,TableModel
也不强制保存该表格显示的数据,
也可以通过TableModel对象来创建表格。
12.11.3 TableColumnModel 和监听器
JTable使用TableColumnModel
来保存该表格所有数据列的状态数据,如果程序需要访问JTable的所有列状态信息,则可以通过获取该JTable的TableColumnModel来实现
12.11.4 实现排序
使用JTable实现的表格并没有实现排序功能,但是可以使用AbstactTableModel类来实现该功能,只要TableModel实现了getValueAt(),getColumnCount(),getRowCount(),
JTable 就可以根据该TableModel生成表格,因此可以创建一个SortableTableModel实现类,将TableModel封装起来,并实现排序功能