Java 图形界面设计

Java 图形界面设计
sinarcsinx图形用户界面(Graphical User Interface,简称 GUI)是大多数程序不可缺少的部分。
Java 的图形界面由各种组件组成。在 java.awt 和 java.swing 包中定义了多种用于创建图形用户界面的组件类。
Swing 组件和 AWT 组件最大的不同是 Swing 组件实现时不包含任何本地代码,因此不受硬件平台的限制,而具有更多的功能,并且在任何平台上运行效果都是相同的。不包含本地代码的 Swing 组件被称为 “轻量级” 组件,而 AWT 被称为 “重量级” 组件。两种组件一同使用的场合,AWT 总是显示在上面。
设计用户界面是一般有 3 个步骤:
- 选取组件
- 设计布局
- 响应事件
容器
组件分为容器组件和非容器组件。容器组件即可以包含其他组件的组件。非容器组件必须包含在容器组件中。
容器组件分为:顶层容器、一般用途容器
顶层容器
Swing 中提供了 4 种顶层容器:
- JFrame:带有标题行和控制按钮(最小化、恢复/最大化、关闭)的独立窗口。有时称为框架。创建程序时要使用 JFream
- JApplet:创建小应用程序时要使用 JApplet。其被包含在浏览器窗口中
- JDialog:创建对话框时使用 JDialog
- JWindow:一个不带有标题行和控制按钮的窗口。一般很少使用
构造方法:
- new JFrame():构造一个初始不可见,无标题的新框架窗体
- new JFrame("Title"):构造一个初始不可见,具有指定标题的新框架窗体
常用方法:
- void setBounds(int x, int y, int width, int height):移动并调整框架大小。框架左上角位置为(x, y),框架大小为 width × height
- void setSize(int width, int height):设置窗口大小
- void setBackground(Color bg):设置框架背景色- void setForeground(Color fg):设置框架前景色
- void setVisible(boolean aFlag):设置可见性
- void pack():自适应框架大小,以符合子组件的首选大小和布局
- void setTitle(String title):设置标题
- Container getContentPane():返回此框架窗体的内容窗格对象- Container 类是所有容器类的父类,包含容器的共有操作 - void setContentPane(Container contentPane):把指定内容窗格设置为此框架的内容窗格对象
- void setLayout(LayoutManager manager):设置布局管理器
内容窗格
4 个顶层容器每个都有 1 个内容窗格。除菜单外,顶层容器的所有组件都放在这个内容窗格内。
- 直接添加组件至内容窗格 - 1 
 2- Container contentPane = jframe.getContentPane(); //[1] 获取内容窗格对象 
 contentPane.add(button, BorderLayout.CENTER); //[2] 将组件添加到内容窗格- 使用顶层容器的 - getContentPane()方法获得其内容窗格对象。
- 将组件添加到内容窗格。 - 其中 button 是一个按钮控件,BorderLayout.CENTER 代表位置在中间 - 向顶层容器内容窗格添加组件时,也可以直接调用顶层容器的 add() 方法 
 
- 以新的内容窗格代替原有内容窗格 - 1 
 2
 3
 4- JPanel contentPane = new JPanel(); //[1] 创建 JPanel 实例 
 contentPane.setLayout(new BorderLayout()); //[2] 创建布局管理器
 contentPane.add(button, BorderLayout.CENTER); //[3] 添加组件
 jfream.setContentPane(contentPane); //[4] 添加内容窗格- 创建 JPanel(面板)实例。JPanel 是 Container 的子类。 
- 顶层容器默认的布局管理器是 BorderLayout,而 JPanel 的默认布局管理器是 FlowLayout 
- 通过 - setContentPane(contentPane)方法为 jfream 设置新的内容窗格
 
面板
普通面板(JPanel)和滚动面板(JScrollPanel)都是用途广泛的容器。面板与顶层容器不同,不能独立存在,而必须添加到其他容器内部。面板可以嵌套,由此可以设计出复杂的图形用户界面。
JPanel
构造方法:
- new JPanel():创建具有 FlowLayout 布局的新面板
- new JPanel(LayoutManager layout):创建指定布局的新面板
常用方法:
- Component add(Compinent comp):将指定组件添加至面板
JScrollPanel
JScrollPanel 是一个带有滚动条的面板,但只能添加一个组件。添加多个组件的场合,先将那些组件添加入 JPanel 对象,再将该 JPanel 对象添加进 JScrollPanel 对象中
构造方法:
- new JScrollPanel():创建一个空的 JScrollPanel。水平、垂直滚动条都能显示
- new JScrollPanel(Component view):创建指定组件内容的 JScrollPanel
常用方法:
- void setHorizontalScrollBarPolicy(int policy):确定水平滚动条何时显示- 其中 policy 的可选值是以下三种: - ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED:需要时可见
- ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER:永远不可见
- ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS:永远可见
 
- void setVerticalScrollBarPolicy(int policy):确定垂直滚动条何时显示- 其中 policy 的可选值是以下三种: - ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED:需要时可见
- ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER:永远不可见
- ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS:永远可见
 
Scrollbar
AWT 中还有一个滚动条组件,提供了允许用户在一定范围的值中进行选择的便捷方式
构造器:
- new Scrollbar():构造一个新的滚动条
- new Scrollbar(int orientation):构造一个有指定方向的滚动条- 其中 orientation 的可选值是: - Scrollbar.HORIZONTAL:水平滚动条
- Scrollbar.VERTICAL:垂直滚动条
 
- new Scrollbar(int orientation, int value, int visible, int minimum, int maximun):构造一个有初始方向、初始值、可视量、最小/最大值的滚动条
标签和按钮
标签
标签(JLable)是最简单的 Swing 组件,通常用于显示提示性的文本信息或图标。其不可被编辑
构造器:
- new JLable():构造一个不显示文本或图标的空标签
- new JLable(Icon image):构造一个显示图标的标签
- new JLable(String text):构造一个显示文本的标签
- new JLable(Icon image, int horizontalAlignment):构造一个显示图标的标签,并指定水平对齐方式- 其中 horizontalAlignment 的取值可以是: - JLable.LEFT:左对齐
- JLable.RIGHT:右对齐
- JLable.CENTER:居中对齐
 
- new JLable(String text, int horizontalAlignment):构造一个显示文本的标签,并指定水平对齐方式
- new JLable(String text, Icon image, int horizontalAlignment):构造一个同时显示文本和图标的标签,并指定水平对齐方式
按钮
按钮(JButton)是 Java 图形用户界面的基本组件之一。
经常用到的按钮有 4 种形式:按钮(JButton)、切换按钮(JToggleButton)、复选按钮(JCheckButton)、单选按钮(JRadioButton)
这些按钮类均是 AbstractButton 的子类或间接子类
JButton
构造器:
- new JButton():构造一个既没有文本也没有图标的按钮
- new JButton(Icon icon):构造一个有图标的按钮
- new JButton(String text):构造一个有文本的按钮
- new JButton(String text, Icon icon):构造一个有文本也有图标的按钮
常用方法:
- void setMnemonic(int mnemonic):设置当前按钮的键盘助记符
- void setText(String text):设置按钮的文本- void setIcon(Icon icon):设置按钮图标
- void setEnabled(boolean mod):是否启用按钮
- String getText():返回按钮的文本
- void setToolTipText():设置提示文本
- void addActionListener(ActionListener l):为按钮添加事件监听程序- void removeActionListener(ActionListener l):移除事件监听程序
JToggleButton、JCheckButton、JRadioButton
JToggleButton 是有两种状态(选中状态、未选中状态)的按钮。通过点击切换这两种状态
JCheckButton、JRadioButton 是 JToggleButton 的子类,构造方法与 JToggleButton 相同。
构造器:
- new JToggleButton():构造一个没有文本也没有图标的切换按钮
- new JToggleButton(Icon icon):构造一个有图标的切换按钮- new JToggleButton(Icon icon, boolean selected):构造一个有图标的切换按钮,设置其初始状态
- new JToggleButton(String text):构造一个有文本的切换按钮- new JToggleButton(String text, boolean selected)
- new JToggleButton(String text, Icon icon):构造一个有文本也有图标的切换按钮- new JToggleButton(String text, Icon icon, boolean selected)
常用方法(除 JButton 方法外):
- boolean isSeleced():获取按钮的当前状态
- void addItemListener(ItemListener l):为按钮添加事件侦听程序- void removeItemListener(ItemListener l):移除事件侦听程序
布局管理器
容器中包含了组件。组件的布局,包括其位置和大小,通常由布局管理器负责安排。每个容器都有一个默认的布局管理器。
FlowLayout 流布局管理器
FlowLayout 定义在 java.awt 包中。
构造器:
- new FlowLayout():创建默认的 FlowLayout 布局管理器。- 居中对齐。默认水平、垂直间距是 5 像素 
- new FlowLayout(int align):创建一个 FlowLayout 布局管理器。- 指定对齐方式。默认水平、垂直间距是 5 像素 - align 的可选值有这些: - FlowLayout.LEFT:左对齐
- FlowLayout.RIGHT:右对齐
- FlowLayout.CENTER:居中对齐
 
- new FlowLayout(int align, int hgap, int vgap):创建一个 FlowLayout 布局管理器。- 指定对齐方式。指定水平、垂直间距 
使用说明:
- FlowLayout 对容器中组件进行布局的方式是将组件逐个放置在容器中的一行上。一行满后,另起一行。
- 与其他布局管理器不同。FlowLayout 不会强行设定组件的大小,而是通过每个组件的 getPreferredSize() 方法获取其各自的期望大小
BorderLayout 边界布局管理器
BorderLayout 定义在 java.awt 包中,是顶层容器的默认布局管理器。它提供了一种较为复杂的组件布局管理方案。
构造方法:
- new BorderLayout():一个组件间没有间距的布局管理器
- new BorderLayout(int hgap, int vgap):定义水平、垂直间距的布局管理器
使用说明:
- 每个由 BorderLayout 管理的容器被划分成 5 个区域,分别是容器的 上部(BorderLayout.NORTH)、下部(BorderLayout.SOUTH)、左部(BorderLayout.WEST)、右部(BorderLayout.EAST)、中部(BorderLayout.CENTER)
- 在 BorderLayout 布局管理器的管理下,组件必须通过 add() 方法加入容器的指定区域。不指定的场合,默认加入中部区域
- 容器的每个区域仅能加入一个组件。加入了多个组件的场合,只有最后一个生效
- 对于中部以外的 4 个边界区域,没有使用的区域的大小将变为零。此时,中部区域会扩展并占据该未用区域的位置。如果 4 个边界区域都没有使用,中部区域会占据整个窗口。
- 窗口大小改变时,按钮的相对位置不会变化。但按钮的大小会改变
GridLayout 网格布局管理器
GridLayout 定义在 java.awt 包中,是一种网格式的布局管理器。
构造器:
- new GridLayout():创建一个一行的网格。列数根据实际需要决定
- new GridLayout(int rows, int cols):指定行数、列数的网格布局- rows 和 cols 中,最多有一个可以是 0,但不能都为 0。那个为 0 的场合,根据实际需要决定数量 
- new GridLayout(int rows, int cols, int hgap, int vgap):指定行数、列数,也指定水平、垂直间距的网格
使用说明:
- GridLayout 将容器空间划分成若干行乘若干列的网格。组件依次放入其中,每个组件占据一格 
- 网格每列宽度相同,每行高度相同。组件放入的次序决定了其位置 
- 想要组件间留有空白的场合,可以添加一个空白标签 
- 网格数多于组件数的场合,那些多余的格子为空白。 - 网格数少于组件数的场合,系统根据需要适当添加。 
- 窗口大小改变时,按钮的相对位置不会变化。但按钮的大小会改变 
CardLayout 卡片式布局管理器
CardLayout 定义在 java.awt 包中,是一种卡片式的布局管理器。
构造器:
- new CardLayout():一个默认无间距的 CardLayout 布局管理器
- new CardLayout(int hgap, int vgap):指定水平、垂直间距的 CardLayout 布局管理器
常用方法:
- void first(Container parent):翻转到容器的第一张卡片- void next(Container parent):翻转到下一张卡片。当前是最后一张的场合,翻到第一张卡片- void previous(Container parent):翻转到前一张卡片。当前是第一张的场合,翻到最后一张卡片- void last(Container parent):翻转到容器的最后一张卡片
- void show(Container parent, String name):翻转到卡片集中具有指定 name 的卡片。没有该卡片的场合不执行任何操作
使用说明:
- CardLayout 将容器中的组件处理为一系列卡片,每一刻只显示其中一张。
- 容器第一次显示时,显示第一个添加的组件。
BoxLayout 方框布局管理器
BoxLayout 定义在 javax.swing 包中,其组件横排一行或竖排一列,但宽度(高度)可以不同。
构造器:
- new BoxLayout(Container target, int axis):创建一个沿给定轴放置组件的布局管理器- 其中 target 表明为哪个容器设置此布局管理器,axis 指明组件排列方向 - axis 的值是: - BoxLayout.X_AXIS:水平方向排列
- BoxLayout.Y_AXIS:竖直方向排列
 - 举个例子: - 1 
 2- JPanel jp = new JPanel(); 
 jp.setLayout(new BoxLayout(jp, BoxLayout.X_AXXIS));
使用说明:
- BoxLayout 将容器中的组件横排一行或竖排一列。那些组件横排一行时,可以有不同宽度;竖排一列时,可以有不同的高度。
- 窗口大小改变时,按钮的相对位置不会变化。
Box 类
javax.swing 中定义了一个专门使用 BoxLayout 的容器 Box 类。
- static Box createHorizontalBox():返回一个使用水平方向的 BoxLayout 的 Box- static Box createVerticalBox():返回一个使用竖直方向的 BoxLayout 的 Box
- static Component createHorizontalGlue():创建一个水平方向的不可视的组件(填满剩余空间)- static Component createVerticalGlue()
- static Component createHorizontalStrut():创建一个水平方向的不可视的组件(指定宽高)- static Component createVerticalStrut()
- static Component createRigidArea():创建一个不可视的组件,不大不小,尺寸真是好极了
空布局
其实也能不用布局管理器的,真的
- 调用容器的 setLayout(null)将容器的布局管理器置空
- =调用组件的 setBounds(x, y, w, h)方法设置其位=置和大小。老东西,你的布局管理器最没用啦!
事件处理
Java 运行时,如果用户进行某个操作,程序应当做出相应。
程 · 序 · 无 · 响 · 应(噔 噔 咚)
……总之,用户在程序界面进行的操作称为用户事件,对事件的相应称为事件处理。
事件处理模型
Java 事件处理是采取 “委派事件模型”。当事件发生时,产生事件类对象。这里说的事件类对象实际上就是
java.awt.event事件类库里某个类创建的对象。操作不同的场合,事件类对象不同。会把此事件类对象传递给事件侦听程序处理。它是实现了对应侦听程序接口的一个类。
事件只是一个对象,其只向注册的侦听程序报告
示范一个简单的事件处理:
| 1 | import javax.seing.*; | 
引入 java.awt.event 包
注册事件侦听程序,并实现其方法
示例中的简写其实相当于以下代码(匿名内部类):
2
3
4
5
6
public void actionPerformed (ActionEvent e) {
System.out.println("Pressed");
}
});事件侦听程序可以定义在单独的类中,也可以定义在组件类中:
2
3
4
5
6
7
8
9
10
public MyButton() {
addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
System.out.println("Pressed");
}
}
事件的种类
在 java.awt.event 包和 javax.swing.event 包中定义了很多其他的事件类。每种事件类有一个对应的接口,接口中声明了一个或多个抽象的事件处理方法。
| 事件类 | 组件 | 方法及说明 | 
|---|---|---|
| ActionEvent | JButton、JCheckBox、JComboBox、JMenuItem、JRaidoButton | actionPerformed(e) 单击按钮、选择菜单项或在文本框中按回车时 | 
| AdjustmentEvent | JScrollBar | adjustmentValueChanged(e) 当改变滚动条滑块位置时 | 
| ComponentEvent | JComponent 及其子类 | componentMoved(e) 组件移动时;componentHidden(e) 组件隐藏时;componenetResized(e) 组件缩时;componentShown(e) 组件显示时 | 
| ContainerEvent | JContainer 及其子类 | containerAdded(e) 添加组件时;containerMoved(e)移除组件时 | 
| FocusEvent | 同 ComponentEvent | focusGained(e) 组件获得焦点时;focusLost(e) 组件失去焦点时 | 
| ItemEvent | JCheckBox、JCheckboxMenuItem、JComboBox | itemStateChanged(e) 选择复选框、选项框、单击列表框、选中带复选框菜单时 | 
| KeyEvent | 同 ComponentEvent | keyPressed(e) 键按下时;keyReleased(e) 键释放时;keyTaped(e) 击键时 | 
| MouseEvent | 同 ComponentEvent | mousePressed(e) 鼠标按下时;mouseEntered(e) 鼠标进入时;mouseExited(e) 鼠标离开时;mouseClicked(e) 鼠标点击时;mouseReleased(e) 鼠标释放时 | 
| MouseMotionEvent | 同 ComponentEvent | mouseDragged(e) 鼠标拖放时;mouseMoved(e) 鼠标移动时 | 
| TextEvent | JTextField、JTextArea | textValueChanged(e) 文本框、多行文本框内容修改时 | 
| WindowEvent | JFrame、JWindow、JDialog | windowOpened(e) 窗口打开时;windowClosing(e) 窗口关闭时;windowClosed(e) 窗口关闭后;windowActived(e) 窗口激活时;windowDeactivated(e) 窗口失去焦点时;windowIconified(e) 窗口最小化时;WindowDeiconified(e) 窗口最小化还原时 | 
使用说明:
- XXXEvent 事件类的接口名就是 XXXListener。占地方太大,上面就没写 
- 事件侦听模式允许为一个组件多次调用 addListener 方法,注册多个侦听程序。 - 事件发生时,单个事件的多个侦听程序的调用顺序不确定。 
- 调用事件处理方法时会传入一个参数。该参数就是那些事件类实例,其中包含事件有关的重要信息。 - 调用这些事件类实例各自特有的方法获取这些信息。 
事件适配器
侦听程序必须实现接口的全部抽象方法,但有时我们只关心其中的某一种方法。为了编程方便,Java 为一些声明了多个抽象方法的 Listener 接口提供了相应的适配器类。
| 接口名称 | 适配器名称 | 
|---|---|
| ComponentListener | ComponentAdapter | 
| ContainerListener | ContainerAdapter | 
| FocusListener | FocusAdapter | 
| KeyListener | KeyAdapter | 
| MouseListener | MouseAdapter | 
| MouseMotionListener | MouseMotionAdapter | 
| MouseInputListener | MouseInputAdapter | 
| WindowListener | WindowAdapter | 
这些适配器实现了接口的全部抽象方法,只是方法内容为空
这样,创建新类时可以不必实现接口,而是继承适配器类,并重写需要的方法
Java 绘图技术
Java 语言约定,显示屏上一个长方形区域为程序绘图区域,坐标原点(0, 0)位于整个区域左上角。
一个坐标点(x, y)对应一个像素,其中坐标点的 x、y 必须是非负整数。x 沿水平方向从左向右递增、y 沿竖直方向从上往下递增
颜色
可以使用 java.awt 包中的 Color 类来定义和管理颜色。Color 类的每个对象代表一种颜色。
Color 类有 26 个常量,代表 13 种预定义颜色:
| 颜色 | 对象 | ᓚᘏᗢ | 
|---|---|---|
| 黑色(#000000) | Color.black | Color.BLACK | 
| 蓝色(#0000FF) | Color.blue | Color.BLUE | 
| 青色(#00FFFF) | Color.cyan | Color.CYAN | 
| 灰色(#808080) | Color.gray | Color.GRAY | 
| 深灰色(#404040) | Color.darkGary | Color.DARKGARY | 
| 浅灰色(#C0C0C0) | Color.lightGary | Color.LIGHTGARY | 
| 绿色(#00FF00) | Color.green | Color.GREEN | 
| 洋红色(#FF00FF) | Color.magenta | Color.MAGENTA | 
| 橙色(#FFC800) | Color.orange | Color.ORANGE | 
| 粉红色(#FFAFAF) | Color.pink | Color.PINK | 
| 红色(#FF0000) | Color.red | Color.RED | 
| 白色(#FFFFFF) | Color.write | Color.WRITE | 
| 黄色(#FFFF00) | Color.yellow | Color.YELLOW | 
也可以通过红、绿、蓝三原色值来组合。每种颜色由三个值组成(RGB),值的范围是 [0, 256):
| 1 | Color color = new Color(102, 204, 255); | 
这个颜色是:天依蓝(#66CCFF)
这部分笔记恐怕是所有 Java 笔记里唯一有五颜六色的地方了,真难得
字体
文字有 字体、样式、字号 三个要素
基本的样式有:
- Font.PLAIN:正常(0) 
- Font.BOLD:粗体(1) 
- Font.ITALIC:_斜体_(2) - 样式可以组合使用,如 (Font.BOLD + Font.ITALIC) 即 粗斜体 
常用的字体:Times New roman(Times New roman)、Symbol(Symbol)、宋体(宋体)、楷体(楷体)等
构造器:
- new Font(String name, int style, int size):新建字体,指定字体、样式、字号
常用方法:
- String getName():返回其字体名称- int getSize():返回其字号大小- int getStyle():返回其样式
- boolean isBold():是否是粗体- boolean isItalic()、- boolean isPlain()
Graphics 类
java.awt 包下的 Graohics 类是所有图形处理的基础,是所有图形上下文的抽象父类。其允许应用程序在组件及屏幕图像上进行绘制。
当先后绘制的图形不同时,确定重叠部分颜色的方法称为绘图模式。
绘图模式分为两种:
- 正常模式: - setPaintMode()- 后绘制的图形覆盖先绘制的图形。 
- 异或模式: - setXORMode(Color c)- 当前绘制的颜色、先前绘制的颜色 及 选定的颜色 c 之间进行某种处理后,用新的颜色绘制。 - 这个模式下,如果使用同一颜色绘制 2 次,则相当于擦除之前绘制的图形,即恢复原本状态。 
若要在某个组件中绘图,应重写该组件的 paint(Graphics g) 方法,并在重写的方法内进行绘图。
- paint(Graphics g):组件被显示出来时,调用该方法- 以下情况该方法会被调用 - 组件第一次在屏幕显示时
- 窗口最小化/最大化
- 窗口大小发生变化
- repaint函数被调用
 
- repaint():重绘组件- 该方法默认情况下会调用以下方法 - paintCompnent(Graphics g):绘制组件- 一般情况下,要在 JComponent 子类的组件中绘图,重写该方法即可 
- class AVL{ public Node root = null; // 根节点 /* 添加一个值(添加一个节点) val:要添加的值 / public void add(int val) { Node toAdd = new Node(val); if (root == null) root = toAdd; else { Node par = root; Node temp = root; while (temp != null) { // 确定其插入位置 par = temp; if (val > temp.val) { temp = temp.right; toAdd.way = true; } else { temp = temp.left; toAdd.way = false; } } if (toAdd.way) { // 将其插入到指定位置 par.right = toAdd; par.right.parent = par; } else { par.left = toAdd; par.left.parent = par; } while (true) { // 维护该平衡二叉树 par = toAVL(par); if (par.parent == null) { root = par; break; } else { if (par.way) par.parent.right = par; else par.parent.left = par; par = par.parent; } } } } / 维护平衡二叉树 root: 待检查节点 / private static Node toAVL(Node root) { if (root == null) return null; int gap = root.rightHeight() - root.leftHeight(); if (Math.abs(gap) > 1) { // |gap| > 1 时,需要旋转 if (gap > 0) { // gap > 0 需要左旋,否则右旋 if (root.right.leftHeight() > root.right.rightHeight()) root.right = roll(root.right, true); return roll(root, false); } else { if (root.left.rightHeight() > root.left.leftHeight()) root.left = roll(root.left, false); return roll(root, true); } } else return root; } / 对该节点进行旋转。 root:待旋转节点 dirR:true 的场合右旋,否则左旋 / private static Node roll(Node root, boolean dirR) { Node temp = null; if (dirR) { temp = root.left; root.left = temp.right; if (temp.right != null) { temp.right.way = false; temp.right.parent = root; } temp.right = root; } else { temp = root.right; root.right = temp.left; if (temp.left != null) { temp.left.way = true; temp.left.parent = root; } temp.left = root; } temp.way = root.way; temp.parent = root.parent; root.way = dirR; root.parent = temp; return temp; } / 一个展示树的方法。供 debug 用 / public static void show(Node root) { LinkedList - a = new LinkedList<>(); LinkedList 一个清点树中节点的方法 */ public static int count(Node root) { if (root == null) return 0; return 1 + count(root.left) + count(root.right); } public static class Node { public int val; // 值 public Node left; // 左节点 public Node right; // 右节点 public Node parent; // 父节点 boolean way = false; // false:该节点是左节点;true:是右节点 public Node(int val) { this.val = val; } public int leftHeight() { // 左子树高度 return (left == null ? 0 : left.height()); } public int rightHeight() { // 右子树高度 return (right == null ? 0 : right.height()); } public int height() { // 该节点树高度 return Math.max(leftHeight(), rightHeight()) + 1; } }}java- b = new LinkedList<>(); a.add(root); while (!a.isEmpty()) { Node temp = a.removeFirst(); System.out.print(temp.val + “ “); if (temp.left != null) b.add(temp.left); if (temp.right != null) b.add(temp.right); if (a.isEmpty()) { System.out.println(); a = b; b = new LinkedList<>(); } } System.out.println(“共 “ + count(root) + “ 个节点”); } / 
- paintChildren(Graphics g):绘制组件的子组件
 
设置画笔:
- setColor(Color c):设置画笔前景色- setBackgroud(Color c):设置背景色- 每个图形环境都有一种画图时正在使用的前景色。画图所在的每个表面都有背景色 
- setFont(Font f):设置画笔字体
绘制几何图案:
- drawArc(int x, int y, int width, int height, int startAngle, int arcAngle):绘制弧线- 该弧线是 沿着起始点为 (x, y)、宽 width、高 height 的矩形所限定的椭圆 绘制一条弧线。 - 该弧线起始角度为 startAngle,弧度角度为 arcAngle - fillArc(int x, int y, int width, int height, int startAngle, int arcAngle):填充扇形
- drawLine(int x1, int y1, int x2, int y2):绘制线段- 该线段的两个端点是 (x1, y1) 和 (x2, y2) 
- drawOval(int x, int y, int width, int height):绘制椭圆- 一个起始点为 (x, y)、宽 width、高 height 的矩形所限定的椭圆 - fillOval(int x, int y, int width, int height):填充椭圆
- drawPolygon(int[] xPoints, int[] tPoints, int nPoints):绘制多边形- drawPolygon(Polygon p):也能通过传入一个 Polygon 对象来绘制多边形- 该图形的端点由传入参数确定。如果最后一个端点和第一个端点不相等,那么图形可能不闭合 - fillPolygon(int[] xPoints, int[] tPoints, int nPoints):填充多边形- fillPolygon(Polygon p):通过传入一个 Polygon 对象来填充多边形- 低情商:这咋填充?高情商:留给读者们思考吧 
- drawRect(int x, int y, int width, int height):绘制矩形- 一个起始点为 (x, y)、宽 width、高 height 的矩形 - fillRect(int x, int y, int width, int height):填充矩形
- drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight):圆角矩形- 一个起始点为 (x, y)、宽 width、高 height 的矩形,其圆角形状由 arcWidth、arcHeight 确定 - 其实就是矩形(线段)和椭圆(圆弧)的某种拼接 - fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight):填充圆角矩形
- drawString(String str, int x, int y):输出字符串- 在 (x, y) 处输出字符串 str,向右扩展 - drawChars(char[] chars, int offSet, int length, int x, int y):输出字符串- 从字符数组的 offSet 下标处起,在 (x, y) 处输出 length 个字符,向右扩展 - drawBytes(byte[] data, int offSet, int length, int x, int y):还不是一样?
- draw3DRect(int x, int y, int width, int height, boolean raised):绘制 3D 矩形- fill3DRect(int x, int y, int width, int height, boolean raised):填充 3D 矩形- 我感觉是和 PS 里的浮雕效果类似,生成了亮部和暗部。rasied 决定是凸起还是凹陷。 
Polygon 类
Polygon 对象封装了多边形的坐标。
构造方法:
- new Polygon():构造一个空的多边形。- 无为太虚,无生一,一生二,二生三,三生万物。所以,空的多边形也是多边形。 
- new Polygon(int[] xs, int[] ys, int n):构造一个 n 点连接成的多边形
常用方法:
- addPoint(int x, int y):将该点加入多边形中
- boolean contains(int x, int y):如果多边形包含该点,则返回真- boolean contains(Point p)
- get Bounds():得到多边形的外接矩形
- translate(int dx, int dy):偏移- 将多边形各点沿 x 轴偏移 dx,再沿 y 轴偏移 dy 
Graphics2D 类
为了解决图形对象的局限性,Java 1.1 后 引入了 Java 2D,其包含一个继承自 Graphics 的 Graphics2D 类,增加了很多状态属性,扩展了 Java 的绘图功能
Graphics2D 拥有强大的二维图形处理能力,提供对几何形状、坐标转换、颜色管理、文字布局等更复杂的控制
图形状态属性
通过设定和修改属性,可以指定画笔宽度和画笔连接方式、设定平移、旋转、缩放或裁剪变换图形,还能设置填充图形的颜色和图案等。
状态属性:
- stroke 属性: - 该属性控制线宽、笔形样式、线段连接方式、短划线图案。 - 使用 - setStroke(Stroke s)方法设置 stroke 属性。- 构造方法: - new BasicStroke(float w):指定线宽的 stroke
- new BasicStroke(float w, int cap, int join):指定线宽、端点样式 cap、线段交汇方式 join 的 stroke- 其中,端点样式 cap 的值可以是: - BasicStroke.CAP_BUTT:无修饰(0)
- BasicStroke.CAP_ROUND:半圆形末端(1)
- BasicStroke.CAP_SQUARE:方形末端(2,默认值)
 - 线段交汇方式 join 的值可以是: - BasicStroke.JOIN_BEVEL:无修饰(2)
- BasicStroke.JOIN_MITER:尖型末端(0,默认值)
- BasicStroke.JOIN_ROUND:圆形末端(1)
 
 
- paint 属性: - 该属性控制填充效果。 - 使用 - setPaint(Paint p)方法设置 paint 属性- 构造方法: - new GradientPaint(float x1, float y1, Color c1, float x2, float y2, Color c2):构造一个简单的非周期性的 paint 对象。- 从点 (x1, y1) 至点 (x2, y2) 处,颜色由 c1 渐变至 c2 
- new GradientPaint(float x1, float y1, Color c1, float x2, float y2, Color c2, boolean cyclic):构造一个周期或非周期性的 paint 对象。- 如果希望渐变至终点又是起点的颜色,将 cyclic 设定为 true 
 
- transform 属性: - 该属性用来实现常用的图形平移、缩放、斜切等 - 使用 - setTransform(Transform t)方法设置 transform 属性- 构造方法: - new AffineTransform():构造一个表示仿射变换的新的 tansform- 仿射变换:用我的话来讲,就是保持坐标点不变的情况下变换坐标系,能形成的变换 
 - 常用方法: - setToRotation(double theta):旋转 theta 角度- setToRotation(double theta, double x, double y):以 (x, y) 为旋转中心旋转- rotate(double theta, double x, double y)
- setToScale(double sx, double sy):拉伸变换- x、y 方向按照 sx、yx 比例变换 - scale(double sx, double sy)
- setToTranslation(double tx, double ty):平移变换- translate(double tx, double ty)
- setToShear(double shx, double shy):斜切变换- shx、shy 分别指定 x、y 方向的斜拉度 
 - 看得出来,出版社的人写到这里应该是到了下班的点了。内容不明不白的不说,还写错了好几处。 - 我笔记上是改过来的。放心。 - 就这还 ”指定教材“ 呢。垃圾,还没我笔记写得好。 
- clip 属性: - 该属性用于实现剪裁效果。 - 使用 - setClip(Shape clip)方法,确定裁剪区域的 Shape。可以连续使用该方法以得到其交集区域
- composit 属性: - 该属性设置图形重叠区域的效果 - 通过 - Alpha.Composite.getInstance(int rule, float alpha)得到一个实例。其中 alpha(透明度)的范围是 [0.0f, 1.0f]- 至于 rule 是什么……我也不知道。或许不重要吧 - 通过 - setComposite(Composite comp)设置混合效果
Graphics2D 的绘图方法
Graphics2D 保留了 Graphics 的绘图方法,又增加了很多新方法
另外,在 java.awt.geom 中声明了一系列类,能用于创建各种几何图形对象,包括:Line2D 线段类、Rectangle2D 矩形类、RoundRectangle2D 圆角矩形类、Ellipse2D 椭圆类、Arc2D 圆弧类、QuadCurve2D 二次曲线类、CubicCurve2D 三次曲线类
这些类都是抽象类,但这些类包中有实现了其方法的 Double 类。
| 1 | ... | 
将 Graphics 对象强制转型为 Graphics2D 对象
创建几何图形对象
这里的 Line2D.Double 表示 Line2D 包下的 Double 类。此处调用了 Double 类的构造器
绘制线段
Graphics2D 中的几何图形类
- new Line2D.Double(int x1, int y1, int x2, int y2):线段- 从 (x1, y1) 到 (x2, y2) 的线段 
- ……(略了略了。相信椭圆、矩形之类的也不用再详细说明了吧) 
- new Arc2D.Double(double x, double y, double w, double h, double start, double extent, int type):弧- 但是特别地,type 的值是以下几种: - Arc2D.OPEN:开弧
- Arc2D.CHORD:弓弧
- Arc2D.PIE:饼弧
 
- new QuadCurver2D.Double(double x1, double y1, double ctrlx, double ctrly, double x2, double y2):绘制二次曲线- 绘制二次曲线需要 3 个点,分别是起始点 (x1, y1)、终点 (x2, y2)、控制点 (ctrlx, ctrly) 
- new CubicCurve2D.Double(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, double ctrly2, double x2, double y2):绘制三次曲线- 绘制三次曲线需要 4 个点,分别是起始点、终点、两个控制点 
组合框与列表
JComboBox 组合框
JComboBox 是一个下拉式菜单。它有两种模式:可编辑的、不可编辑的。
对于不可编辑的 JComboBox,用户只能在现有列表中进行选择
对于可编辑的 JComboBox,用户既能在现有选项中选择,也能输入新的内容
构造方法:
- new JComboBox<E>():创建一个 E 类型(泛型)的没有任何可选项的默认组合框
- new JComboBox<E>(E[] items):根据 items 数组创建组合框- items 数组元素即为组合框的可选项 
常用方法:
- void setEditable(boolean aFlag):设置可编辑性- 不设置的场合,默认处于不可编辑状态 
- void addItem(E item):在末尾添加可选项- void insertItemAt(E item, int index):在指定下标处添加可选项
- void removeAllItems():删除所有可选项- void removeItem(E iten):删除 item 指定的可选项- void removeItemAt(int index):删除指定下标处的可选项
- E getItemAt(int index):获取指定下标的可选项
- int getItemCount():获取列表项数
- int getSelectedIndex():获取选中项匹配的第一个选项的索引下标- E getSelectedItem():获取选中项
JList 列表
JList 是可供用户选择的一系列可选项
构造方法:
- new JList<E>():构造一个空列表
- new JList<E>(E[] listData):构造一个列表,可选元素由 listData 指定
- new JList<E>(Vector<E> listData):构造一个列表,使其显示指定 Vector 中的元素
常用方法:
- addListSelectionListener(ListSelectionListener l):添加监视器- 当用户在列表上选择时,会触发 ListSelectionEvent 事件。 - 在 ListSelectionListener 接口中,仅有一个方法: - 1 - void valueChanged(ListSelectionEvent e); - 当列表的当前选项改变时,会调用该方法。 
- int getSelectedIndex():返回选中项第一次出现的下标索引- 没有选中项的场合,返回 -1 - E getSelectedValue():返回所选的第一个值- 没有选中项的场合,返回 null 
- void setVisableRowCount(int count):设置不使用滚动条可以在列表中显示的选项行数
- void setSelectionMode(int mode):设置列表的选择模式- 其中,mode 的值可以是以下几种: - ListSelectionModel.SINGLE_SELECTION:仅支持单项选择(0)
- ListSelectionModel.SINGLE_INTERVAL_SELECTION:可多选,但多个选项必须是连续的(1)
- ListSelectionModel.MULTIPLE_INTERVAL_SELECTION:可多选(2,默认值)
 
文本组件
文本组件可以提示信息和提供用户输入功能。Swing 中提供了 JTextField(文本域)、JPasswordField(口令输入域)、JTextArea(文本区)等多个文本组件。
文本组件的共同的父类是 JTextComponent,其中定义了文本组件的共有方法:
- String getSelectedText():从文本组件中提取被选中的文本内容
- String getText():从文本组件中提取全部文本内容- String getText(int offs, int len):从文本组件中提取指定范围的文本内容
- void select(inr start, int end):在文本组件中选中指定范围内容- void selectAll():在文本组件中选中全部内容
- void setEditable(boolean b):设置可编辑状态
- void setText(String t):设置文本组件的文本内容
- void setDocument(Document doc):设置文本组件的文档
- void copy():复制选中文本至剪贴板- void cut():剪切选中文本至剪贴板- void paste():粘贴剪贴板内容至当前位置
另外,JComponrnt 类中有如下方法:
- boolean requestFocusInWindow():请求当前组件获得输入焦点
JTextField 文本域
文本域是一个单行的文本输入框,可以用于输入少量文本
构造方法:
- new JTextField():构造一个空文本域
- new JTextField(int columns):构造一个指定列数的空文本域- 由于组件大小通常由布局管理器确定,因此指定的列数可能被忽略 
- new JTextField(String text):构造一个显示指定初始字符的文本域
- new JTextField(String text, int columns):构造一个指定列数及初始字符的文本域
常用方法:
- void addActionListener(ActionListener l):添加指定侦听器- void removeActionListener(ActionListener l):移除指定侦听器
- void setFont():设置当前字体
- void setHorizontalAlignment(int alignment):设置水平对齐方式- 有效值包括: - JTextField.LEFT:左对齐(2) 
- JTextField.RIGHT:右对齐(4) 
- JTextField.CENTER:居中对齐(0) 
- JTextField.LEADING:领先对齐(10) - (似乎是)识别文字前端的对齐方式……好吧,我也不太明白 
- JTextField.TRAILING:落后对齐(11) 
 
- int getColumns():返回文本域列数
JTextArea 文本区
JTextArea 是一个多行多列的文本输入框
构造方法:
- new JTextArea():构造一个空文本区
- new JTextArea(int rows, int columns):构造一个指定行数、列数数的空文本区
- new JTextArea(String text):构造一个显示指定初始字符的文本区
- new JTextArea(String text, int rows, int columns):构造一个指定行列数及初始字符的文本区
常用方法:
- void append(String str):追加文本到文本区
- void insert(String str, int pos):将指定文本插入到特定位置 pos 处
- void replaceRange(String str, int start, int end):用指定文本 str 替换指定范围的文本
- void addAncestorListener(AncestorListener listener):添加指定侦听器- 特别地,用户输入文本时,按下 Enter 键的场合只是向缓冲区输入一个字符,而不能表示输入的结束。因此,需要识别用户输入完成时,通常要在文本区旁放置一个确定按钮 
菜单组件
菜单是最常用的 GUI 组件之一。Swing 包中提供了多种菜单组件。
菜单有下拉式菜单和弹出式菜单两种
菜单栏及菜单
JMenuBar 菜单栏是窗口主菜单,用来包容一组菜单
通过容器的
setJMenuBar(JMenuBar m)方法将菜单栏放到窗口上
菜单栏 JMenuBar 构造方法:
- new JMenuBar():构建一个新的菜单栏
菜单栏也能注册一些事件侦听程序,但通常情况下对于这些事件我们都不进行处理
菜单构造方法:
- new JMenu():构造没有文本的新菜单
- new JMenu(String str):构造有指定标签的菜单
- new JMenu(String str, boolean b):构造有指定标签的菜单,并指示其是否可以被分离
常用方法:
- add(JMenu m):菜单可以被加入菜单栏或另一个菜单中
- addSeparator():为菜单各项间加入间隔线- insertSeparator(int index):在指定位置插入间隔线- 也能通过这种方式插入间隔线: - 1 - menu.add(new JSeparator()); //JSeparator 类即分割线类 
JMenuItem 菜单项
JMenuItem 菜单项是菜单系统的最下一级
构造方法:
- new JMenuItem():创建不带有设置文本或图标的菜单项
- new JMenuItem(Icon i):创建只有图标的菜单项
- new JMenuItem(String str):创建只有文本的菜单项
- new JMenuItem(String str, Icon i):创建有图标和文本的菜单项
- new JMenuItem(String str, int mnemonic):创建有文本和快捷键的菜单项- 那个快捷键的有效值是 KeyEvent 包下的各种常量 
常用方法:
- setMnemonic(int m):设置快捷键
- setAccelerator(KeyStroke keyStroke):设置加速键
- addActionListener(ActionListener l):加入侦听器- 菜单项被选中时,会触发 ActionEvent 事件 
复选菜单项和单选菜单项
JCheckBoxMenuItem(复选菜单项)和 JRadioButtonMenuItem(单选菜单项)是两种特殊的菜单项。
JCheckBoxMenuItem 前有个小方框,以供提示复选
JRadioButtonMenuItem 前有个小圆圈,以供提示单选
复选菜单项构造器:
- new JCheckBoxMenuItem():一个无文本图标,初始未选中的菜单项
- new JCheckBoxMenuItem(Icon i):就是有图标咯
- new JCheckBoxMenuItem(String str):就是有文本咯
- new JCheckBoxMenuItem(String str, boolean b):就是有文本,又指定初始状态咯
- new JCheckBoxMenuItem(String str, Icon i):就是有文本,又有图标咯
- new JCheckBoxMenuItem(String str, Icon i, boolean b):你猜呗
单选菜单项构造器:
单选菜单项是 JRadioButtonMenuItem,剩下的都和上面的一样
对话框
对话框是一个临时的可移动窗口,其依赖于其他窗口。当期依赖的窗口消失或最小化时,对话框消失。窗口还原时对话框恢复。
对话框分为强制型和非强制型。强制型对话框在关闭前,其他窗口不能接收任何形式的输入。也就是说,该对话过程不能中断。强制型对话框也被称为模式窗口。
JDialog 自定义对话框
构造方法:
- new JDialog(Dialog owner):无标题无模式对话框。指定对话框为其所有者- new JDialog(Frame owner):指定框架为其所有者
- new JDialog(Dialog owner, boolean model):无标题对话框,指定所有者并指示是否为有模式
- new JDialog(Dialog owner, String title)- new JDialog(Frame owner, String title)- new JDialog(Dialog owner, String title, boolean model)- new JDialog(Frame owner, String title, boolean model):这些你都懂的吧
JOptionalPane 标准对话框
JDialog 通常用于创建自定义对话框。此外,还有用于显示标准对话框的 JOptionalPane 类
JOptionalPane 定义了多个静态方法,分为以下 4 个类型:
- showConfirmDialog:确认对话框。显示问题,要求用户进行确认(yes / no / cancel) - 其同名方法有以下 3 种 - int showConfirmDialog(Component parentComponent, Object message) 
- int showConfirmDialog(Component parentComponent, Object message, String title, int optionType) 
- int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType) 
 
- showInputDialog:输入对话框。提示用户进行输入 - 同名方法有以下 6 种: - showInputDialog(Object message) 
- showInputDialog(Object message, Object initialValue) 
- showInputDialog(Component parentComponent, Object message) 
- showInputDialog(Component parentComponent, Object message, Object initialValue) 
- showInputDialog(Component parentComponent, Object message, String title, int messageType) 
- showInputDialog(Component parentComponent, Object message, String title, int messageType, Icon icon, Object[] options, Object initialValue) 
 
- showMessageDialog:信息对话框。显示信息 - 同名方法有以下 3 种: - showMessageDialog(Component parentComponent, Object message) 
- showMessageDialog(Component parentComponent, Object message, String title, int messageType) 
- showMessageDialog(Component parentComponent, Object message, String title, int messageType, Icon icon) 
 
- showOptionDialog:选项对话框,显示选项,要求用户进行选择 - 其只有 1 种同名方法 - showOptionDialog(Component parentComponent, Object message, String title, int optionType, int messageType, Icon icon, Object[] options, Object initialValue)
 
以上各个方法的参数分别是:
- Component parentComponent:对话框的父窗口对象。其父窗口位置决定了对话框位置 - 该值可以是 null,表示用默认的 Frame 作为父窗口。这个场合,对话框位置在屏幕正中 
- Object message:显示在对话框的描述信息。 - 该参数通常是 String 对象,但也能是一个图标、组件或对象数组 
- String title:对话框标题 
- int optionType:对话框上的按钮类型。可以是以下常量: - JOptionalPane.DEFAULT_OPTION:默认(-1)
- JOptionalPane.YES_NO_OPTION:一组 yes / no(0)
- JOptionalPane.YES_NO_CANCEL_OPTION:一组 yes / no / cancel(1)
- JOptionalPane.OK_CANCEL_OPTION:一组 ok / cancel(2)
 - 此外,也能通过 Object[] options 参数指定其他形式 
- Object[] options:对话框上的选项。 - 在输入对话框中,通常以组合框架形式显示。在选项对话框中,则是指按钮类型。 - 该参数通常是一个 String[] 数组,但也能是图标数组或组件数组 
- int messageType:对话框传递的信息类型。可以是以下常量: - JOptionalPane.ERROR_MESSAGE:错误信息(0)
- JOptionalPane.INFORMATION_MESSAGE:普通信息(1)
- JOptionalPane.WARNING_MESSAGE:警告信息(2)
- JOptionalPane.QUESTION_MESSAGE:提问信息(3)
- JOptionalPane.PLAIN_MESSAGE:无格式信息(-1)
 - 除 PLAIN_MESSAGE 外,每种类型对应于一个默认的图标 
- Object initialValue:初始选项或输入值 
JFileChooser 文件对话框
JFileChooser 文件对话框是专门用于对文件或目录进行浏览和选择的对话框
构造方法:
- new JFileChooser():构造一个指向客户默认目录的文件对话框
- new JFileChooser(File currentDirectory):指向指定目录的文件对话框
- new JFileChooser(String path):指向指定目录的文件对话框
常用方法:
- showOpenDialog(Component parent):弹出一个 “打开” 文件对话框- parent 是对话框的父窗口对象。其父窗口位置决定了对话框位置 - 该值可以是 null,表示用默认的 Frame 作为父窗口。这个场合,对话框位置在屏幕正中 - showSaveDialog(Component parent):弹出一个 “保存” 文件对话框
- getSelectedFile():获得用户选择的文件







