Java图形可视化编程
发表于:2024-02-04 | 分类: java学习笔记

JAVA图形化界面编程

一、 AWT编程

AWT是“抽象窗口工具集”,它为Java应用程序提供了基本的图形组件,AWT是窗口框架,它从不同平台的窗口系统中抽取共同组件,当程序运行时,将这些组件的创建和动作委托给程序所在的运行平台。简而言之,当使用AWT编写图形界面应用时,程序仅指定了界面组件的位置和行为,并未实现真正的实现,Java调用操作系统本地的图形界面来创建和平台一致的对等体。

AWT继承体系:

AWT编程中有两个基类:Component和MenuComponent。

  • Component: 代表一个能以图形化方式显示出来,并可以与用户交互的对象,例如Button代表一个按钮,TexField代表一个文本框等;
  • MenuComponent: 代表图形界面的菜单组件,包括MenuBar(菜单条)、MenuItem(菜单项)等子类。

其中Container是一种特殊的Component,它代表一种容器,可以盛装普通的Component.

AWT还有一个非常重要的接口叫做LayoutManager,如果一个容器中有多个组件,那么容器就需要使用LayoutManager来管理这些组件的布局方式。

1.Container容器

Container容器继承体系

  • Window是可以独立存在的顶级窗口,默认使用BorderLayout管理其内部组件布局;
  • Panel可以容纳其他组件,但不能独立存在,它必须内嵌其他容器使用,默认使用FlowLayout管理其内部组件布局;
  • ScrollPane是一个带滚动条的容器,它也不能独立存在,默认使用BorderLayout管理其内部组件布局;

常见API

Component作为基类,提供了如下常用的方法来设置组件的大小,位置,可见性等。

方法名 方法说明
setLocation(int x,int y) 设置组件的位置
setSize(int width,int height) 设置组件的大小
setBounds(int x,int y,int width,int height) 同时设置组件的位置,大小
setVisible(Boolean b) 设置该组件的可见性

Container作为容器根类,提供了如下方法来访问容器中的组件

方法名 方法说明
Component add(Component comp) 向容器中添加其他组件(该组件既可以是普通组件,也可以是容器)
Component getComponentAt(int x,int y) 返回指定点的组件
int getComponentCount() 返回该容器内组件的数量
Component[] getComponents() 返回该容器内的所有组件

演示1(Window):

1
2
3
4
5
6
7
8
9
10
import java.awt.*;
public class Main {
public static void main(String[] args) {
//创建一个窗口对象 指定窗口的位置,大小(单位是像素) 设置窗口对象可见
Frame frame=new Frame("这里是Window测试窗口:");
frame.setLocation(100,100);
frame.setSize(500,300);
frame.setVisible(true);
}
}

演示2(Panel):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.awt.*;
public class Main {
public static void main(String[] args) {
//创建一个Window对象,Panel对象以及其他的容器都不能独立存在,必须依附于Window存在
//1.创建一个Panel对象
//2.创建一个文本框和一个按钮,并且把他们放入到Panel容器中
//3.把panel放入到Window中
//4.设置Window的位置 大小
//5.设置Window可见
Frame frame=new Frame("演示Panel:");
Panel p=new Panel();
p.add(new TextField("这是一个测试文本"));
p.add(new Button("这是一个测试按钮"));
frame.add(p);
frame.setBounds(100,100,500,300);
frame.setVisible(true);
}
}

演示3(ScrollPane):

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.awt.*;
public class Main {
public static void main(String[] args) {
Frame frame=new Frame("演示ScrollPane:");
ScrollPane s=new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS);//创建ScrollPane对象 滚动条
s.add(new TextField("这是一个测试文本"));
s.add(new Button("这是一个测试按钮"));
frame.add(s);
frame.setBounds(100,100,500,300);
frame.setVisible(true);
}
}

2.Layoutmanager管理器

LayoutManager布局管理器,可以根据运行平台来自动调整组件大小,程序员不用再手动设置组件的大小和位置了,只需要为容器选择合适的布局管理器即可。

1.FlowLayout

​ 在flowLayout布局管理器中,组件像水流一样向某方向流动(排列),遇到障碍(边界)就折回。重头开始排列。在默认的情况下,FlowLayout布局管理器从左向右排列所有组件,遇到边界就会折回下一行重新开始。

构造方法 方法说明
FlowLayout() 使用默认的对齐格式以及默认的垂直间距、水平间距创建FlowLayout布局管理器。
FlowLayout(int align) 使用指定的对齐格式以及默认的垂直间距、水平间距创建FlowLayout布局管理器。
FlowLayout(int align,int hgap,int vgap) 使用指定的对齐格式以及指定的垂直间距、水平间距创建FlowLayout布局管理器。

FlowLayout中组件的排列方向(从左到右、从右到左,从中间到两边等等),该参数应该使用FlowLayout类的静态常量:

FlowLayout.LEET、FlowLayout.CENTER、FlowLayout.RIGHT,默认是左对齐。

FlowLayout中组件中间间距通过整数设置,单位是像素,默认是5个像素。

代码演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.awt.*;
public class Main {
public static void main(String[] args) {
Frame frame=new Frame("演示FlowLayout:");
//1.通过setLayout方法设置容器的布局管理器
//frame.setLayout(new FlowLayout(FlowLayout.LEADING,20,30));
frame.setLayout(new FlowLayout(FlowLayout.CENTER,40,20));
//2.添加多个按钮
for(int i=1;i<=100;i++){
frame.add(new Button("按钮"+i));
}
//3.设置最佳大小,pack方法
frame.pack();
frame.setVisible(true);
}
}

2.BorderLayout

​ Borderlayout将容器分为EAST、SOUTH、WEST、NORTH、CENTER五个区域,普通组件可以被放置在这5个区域的任意一个中。

当改变使用BorderLayout的容器大小时,NORTH、SOUTH、和CENTER区域水平调整,而EAST、WEST和CENTER区域垂直调整。使用BorderLayout有如下两个注意点:

  • 当向BorderLayout布局管理器的容器中添加组件时,需要指定添加到哪个区域中。如果没有指定添加到哪个区域,则默认添加到中间区域中;
  • 如果向同一个区域中添加多个组件时,后放入的组件会覆盖先放入的组件;
构造方法 方法说明
BorderLayout() 使用默认的水平间距、垂直间距创建BorderLayout布局管理器
BorderLayout(int hgap,int vgap) 使用指定的水平间距、垂直间距创建BorderLayout布局管理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.awt.*;
public class Main {
public static void main(String[] args) {
Frame frame=new Frame("演示 BorderLayout:");
//1.指定Frame对象的布局管理器为BorderLayout
frame.setLayout(new BorderLayout(30,10));
//2.往Frame指定东西南北各添加一个按钮组件
frame.add(new Button("北侧按钮"), BorderLayout.NORTH);
frame.add(new Button("南侧按钮"), BorderLayout.SOUTH);
frame.add(new Button("东侧按钮"), BorderLayout.EAST);
frame.add(new Button("西侧按钮"), BorderLayout.WEST);
frame.add(new Button("中间按钮"), BorderLayout.CENTER);
//3.设置最佳大小,pack方法
frame.pack();
frame.setVisible(true);
}
}

如果不往某个区域放入组件,那么该区域不会空白出来,而是会被其他区域占用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.awt.*;
public class Main {
public static void main(String[] args) {
Frame frame=new Frame("演示 BorderLayout:");
//1.指定Frame对象的布局管理器为BorderLayout
frame.setLayout(new BorderLayout(30,10));
//2.往Frame指定东西南北各添加一个按钮组件
frame.add(new Button("北侧按钮"), BorderLayout.NORTH);
frame.add(new Button("南侧按钮"), BorderLayout.SOUTH);
//frame.add(new Button("东侧按钮"), BorderLayout.EAST);
// frame.add(new Button("西侧按钮"), BorderLayout.WEST);
frame.add(new Button("中间按钮"), BorderLayout.CENTER);
Panel p=new Panel();
p.add(new Button("中间按钮"));
p.add(new TextField("测试文本框"));
frame.add(p);
//3.设置最佳大小,pack方法
frame.pack();
frame.setVisible(true);
}
}

3.GirdLayout

​ GirdLayout布局管理器将容器分割成纵横线分隔的网格,每个网格所占的区域大小相同,当向使用GirdLayout布局管理器中的容器中添加组件时,默认从左至右、从上至下依次添加到每个网格中,与FlowLayout不同的是,

放置在GirdLayout布局管理器中的各组件的大小由组件所处的区域决定(每个组件将自动占满整个区域)。

构造方法 方法说明
GirdLayout(int rows,int cols) 采用指定的行数和列数,以及默认的横向间距、纵向间距将容器分割成多个网格
GirdLayout(int rows,int cols,int hgap,int vgap) 采用指定的行数和列数,以及指定的横向间距、纵向间距将容器分割成多个网格

案例:

​ 使用Frame+Panel,配合FlowLayout和GirdLayout完成一个计算器效果。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import org.w3c.dom.Text;

import java.awt.*;
public class Main {
public static void main(String[] args) {
Frame frame=new Frame("计算器");
//1.创建一个Panel对象,里面存放一个TextField组件
Panel p=new Panel();
p.add(new TextField(30));
//2.把当前这个Panel添加到frame的北边区域
frame.add(p,BorderLayout.NORTH);

//3.创建一个Panel对象,并且设置它的布局管理器为GridLayout
Panel p2=new Panel();
p2.setLayout(new GridLayout(3,5,4,4));

//4.往Panel中添加内容
for(int i=0;i<=9;i++){
p2.add(new Button(i+""));
}
p2.add(new Button("+"));
p2.add(new Button("-"));
p2.add(new Button("*"));
p2.add(new Button("/"));
p2.add(new Button("."));


//5.把当前Panel添加到frame中
frame.add(p2);

frame.pack();
frame.setVisible(true);
}
}

4.GirdBagLayout

​ GirdBagLayout布局管理器的功能最强大,但也是最复杂,与GirdLayout布局管理器不同的是,在GirdBagLayout布局管理器中,一个组件可以跨越一个或者多个网格,并可以设置各网格的大小互不相同,从而增强了布局的灵活性。当窗口的大小发生变化时,GirdBagLayout布局管理器可以准确控制窗口各部分的拉伸。

由于在GirdBagLayout布局中,每个组件可以占用多个网络,此时,我们往容器中添加组件时,就需要具体的控制每个组件占用多少网格,java提供的GridBagConstains类,与特定的组件绑定,可以完成具体大小和跨越性的设置

5.CardLayout

​ 以时间而非空间来管理它里面的组件,它将加入到的容器所有的组件看成一叠卡片,每个卡片其实就是一个组件,每次只有最上面的Component才可见。

方法名称 方法功能
CardLayout() 创建默认的CardLayout布局管理器
CardLayout(int hgap,int vgap) 通过指定卡片与容器左右边界的间距C hgap)、上下边界Cvgap)的间距来创建CardLayout布局管理器
first(Container target) 显示target容器中的第一张卡片
last(Container target) 显示target容器中的最后一张卡片
previous(Container target) 显示target容器中的前一张卡片
next(Container target) 显示target容器中的后一张卡片
show(Container target,String name) 显示target容器中指定名字的卡片

案例:

​ 使用Frame和Panel以及CardLayout完成下图中的效果,点击底部按钮,切换卡片

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Main {
public static void main(String[] args) {
Frame frame = new Frame("CardLayout");
//创建一个Panel储存多个卡片
Panel panel = new Panel();
//创建CardLayout对象,并且把该对象设置到容器中
CardLayout cardLayout = new CardLayout();
panel.setLayout(cardLayout);
//往panel中储存多个组件
String[] names = {"第一张", "第二张", "第三张", "第四张", "第五张",};
for (int i = 0; i < names.length; i++) {
panel.add(names[i], new Button(names[i]));

}
//把panel放到frame中间区域
frame.add(panel);

//船舰另外一个panel存放底部按钮组件
Panel panelButton = new Panel();
//创建5个按钮组件
Button b1 = new Button("上一张");
Button b2 = new Button("下一张");
Button b3 = new Button("第一张");
Button b4 = new Button("最后一张");
Button b5 = new Button("第三张");
//创建一个事件监听器对象,用于监听按钮
ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//获取按钮对象
String actionCommand = e.getActionCommand();
switch (actionCommand) {
case "上一张":
cardLayout.previous(panel);
break;
case "下一张":
cardLayout.next(panel);
break;
case "第一张":
cardLayout.first(panel);
break;
case "最后一张":
cardLayout.last(panel);
break;
case "第三张":
cardLayout.show(panel, "第三张");
break;

}

}
};
//把当前这个事件监听器和多个按钮绑定到一起
b1.addActionListener(actionListener);
b2.addActionListener(actionListener);
b3.addActionListener(actionListener);
b4.addActionListener(actionListener);
b5.addActionListener(actionListener);
//把按钮添加到容器中
panelButton.add(b1);
panelButton.add(b2);
panelButton.add(b3);
panelButton.add(b4);
panelButton.add(b5);
//把panelButton存放的frame的那边区域
frame.add(panelButton, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}

6.BoxLayout

为了简化开发,Swing引入了一个新的布局管理器:BoxLayout。BoxLayout可以在水平和垂直两个方向上摆放GUI组件,BoxLayout提供了如下一个简单的构造器:

方法名称 方法功能
BoxLayout(Container target,int axis) 指定创建基于target容器的BoxLayout布局管理器,该布局管理器里的组件按照axis方向排列,其中axis有BoxLayout.X_AXIS(横向)和BoxLayout.Y.AXIS(纵向)两个方向。

案例1:

​ 使用Frame和BoxLayout完成下图效果

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package AWT;
import java.awt.*;
import javax.swing.*;
public class BoxLayoutDemo1 {
public static void main(String[] args) {

Frame frame = new Frame("BoxLayout");
//创建BoxLayout对象,该对象的组件垂直存放
// BoxLayout boxLayout = new BoxLayout(frame,BoxLayout.X_AXIS);
BoxLayout boxLayout = new BoxLayout(frame,BoxLayout.Y_AXIS);
//把boxlayout对象设置给frame
frame.setLayout(boxLayout);
//创建两个按钮组件
frame.add(new Button("buttonOne"));
frame.add(new Button("buttonTwo"));
frame.pack();
frame.setVisible(true);
}
}

​ 在java.swing包中,提供了一个新的容器Box,该容器的默认布局管理器就是BoxLayout,大多数情况下使用Box容器去容纳多个GUI组件,然后把Box容器作为一个组件,添加到其他容器中,从而形成整体窗口布局。

方法名称 方法功能
static Box createHorizontalBox() 创建一个水平排列组件的Box容器
static Box createVerticalBox() 创建一个垂直排列组件的Box容器

案例2:

​ 使用Frame和Box,完成下图效果。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package AWT;
import java.awt.*;
import javax.swing.*;
public class BoxLayoutDemo2 {
public static void main(String[] args){
Frame frame = new Frame("BoxLayout");
//创建Box水平排列组件的容器
Box horizontalBox = Box.createHorizontalBox();
//往容器中添加按钮
horizontalBox.add(new Button("HButtonOne"));
horizontalBox.add(new Button("HButtonTwo"));
//创建Box垂直排列组件的容器
Box verticalBox = Box.createVerticalBox();
//往容器中添加按钮
verticalBox.add(new Button("VButtonOne"));
verticalBox.add(new Button("VButtonTwo"));
//把容器添加到frame中
frame.add(horizontalBox,BorderLayout.NORTH);
frame.add(verticalBox);
frame.pack();
frame.setVisible(true);
}
}

​ Box实现间隔组件

方法名称 方法说明
static Component createHorizontalGlue() 创建一条水平Glue(可在两个方向上同时拉伸的间距)
static Component createVerticalGlue() 创建一条垂直Glue(可在两个方向上同时拉伸的间距)
static Component createHorizontalStrut(int width) 创建一条指定宽度(宽度固定了,不能拉伸)的水平Strut(可在垂直方向上拉伸的间距)
static Component createVerticalStrut(int height) 创建一条指定高度(高度固定了,不能拉伸)的垂直Strut(可在水平方向上拉伸的间距)

案例3:

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package AWT;
import java.awt.*;
import javax.swing.*;
public class BordLayoutDemo3 {
public static void main(String[] args) {
Frame frame = new Frame("BoxLayout");
//船舰水平排列的Box容器
Box horizontalBox = Box.createHorizontalBox();
//往容器中添加按钮和间隔
horizontalBox.add(new Button("HButtonOne"));
horizontalBox.add(Box.createHorizontalGlue());//默认间隔
horizontalBox.add(new Button("HButtonTwo"));
horizontalBox.add(Box.createHorizontalStrut(30));//指定间隔
horizontalBox.add(new Button("HButtonThree"));
//创建垂直排列的容器
Box verticalBox = Box.createVerticalBox();
//往容器中添加按钮和间隔
verticalBox.add(new Button("VButtonOne"));
verticalBox.add(Box.createVerticalGlue());
verticalBox.add(new Button("VButtonTwo"));
verticalBox.add(Box.createVerticalStrut(30));
verticalBox.add(new Button("VButtonThree"));
//把box容器添加到frame中
frame.add(horizontalBox,BorderLayout.NORTH);
frame.add(verticalBox);
frame.pack();
frame.setVisible(true);
}
}

3.常用组件

3.1基本组件

组件名 功能
Button 按钮
Canvas 用于绘画的画布
Checkbox 复选框组件(也可当作单选框组件使用)
CheckboxGroup 用于将多个Checkbox组件合成一组,一组Checkbox组件中将只有一个可以被选中,即全部变成单选框组件
Choice 下拉选择框
Frame 窗口,在GUI程序里通过该类创建窗口
Label 标签类,用于放置提示性文本
List 列表框组件,可以添加多项条目
Panel 不能单独存在基本容器类,必须放置到其他容器中
Scrollbar 滑动条组件,如果需要用户输入某个范围中的值,就可以使用滑动条组件,比如调色板中设置RGB的三个值所用的滑动条。当创建一个滑动条时,必须指定它的方向、初始值、滑块的大小、最小值和最大值。
ScrollPane 带水平和垂直滚动条的容器组件
TextArea 多行文本域
TextField 单行文本框

案例:

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package AWT;
import java.awt.*;
import javax.swing.*;
public class BasicComponentDemo {
Frame frame=new Frame("这里是测试组件");
TextArea ta=new TextArea(5,20);
Choice colorChoice=new Choice();
CheckboxGroup cbg=new CheckboxGroup();
Checkbox male=new Checkbox("男",cbg,true);
Checkbox female=new Checkbox("女",cbg,false);
Checkbox isMarried=new Checkbox("是否已婚");

TextField tf=new TextField(50);
Button ok=new Button("ok");
List colorList=new List(6,true);
public void init(){
//组装界面

//组装底部
Box bBox= Box.createHorizontalBox();
bBox.add(tf);
bBox.add(ok);
frame.add(bBox,BorderLayout.SOUTH);

//组装选择部分
colorChoice.add("红色");
colorChoice.add("蓝色");
colorChoice.add("绿色");
Box cBox=Box.createHorizontalBox();
cBox.add(colorList);
cBox.add(male);
cBox.add(female);
cBox.add(isMarried);

//组装文本域和选择部分
Box topLeft=Box.createHorizontalBox();
topLeft.add(ta);
topLeft.add(cBox);

//组装顶部左边和列表框
colorList.add("红色");
colorList.add("蓝色");
colorList.add("绿色");
Box top=Box.createHorizontalBox();
top.add(topLeft);
top.add(colorList);

frame.add(top);

//设置frame为最佳大小 可见
frame.pack();
frame.setVisible(true);

}
public static void main(String[] args){
new BasicComponentDemo().init();


}
}

3.2对话框Dialog

3.2.1 Dialog

Dialog是windos类的子类,是一个容器,属于特殊组件,对话框可以独立存在的顶级窗口,和普通窗口用法一样。

  • 使用对话框通常依赖其他窗口,就是通常有一个父窗口。
  • 对话框分为非模式和模式两种,当某个模式被打开之后该模式对话框位于它的父窗口之上,在模式对话框被关闭之前,父窗口无法获取焦点。

案例1:

​ 通过Frame、Button、Dialog实现下图效果:

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package AWT;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class DialogDemo1 {
public static void main(String[] args){
Frame frame=new Frame("这里测试Dialog");

//1.创建两个对话框Dialog对象,一个模式的,一个非模式的
Dialog d1=new Dialog(frame,"模式对话框",true);
Dialog d2=new Dialog(frame,"非模式对话框",false);

//2.通过setBounds方法设置Dialog组件的位置以及大小
d1.setBounds(20,30,300,200);
d2.setBounds(20,30,300,200);


//3.创建两个按钮
Button b1=new Button("按钮1:打开模式对话框");
Button b2=new Button("按钮2:打开非模式对话框");

//4.给这两个按钮添加点击后的行为
b1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
d1.setVisible(true);
}
});
b2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
d2.setVisible(true);
}
});
//5.把按钮添加到frame中
frame.add(b1,BorderLayout.NORTH);
frame.add(b2,BorderLayout.SOUTH);

frame.pack();
frame.setVisible(true);

}
}

案例2:

​ 设置如下图效果:

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package AWT;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class DialogDemo2 {
public static void main(String[] args){
Frame frame=new Frame("这里是测试Dialog");

//1.创建两个对话框Dialog对象,一个模式的
Dialog d1=new Dialog(frame,"模式对话框",true);

//创建一个垂直的Box容器把文本框和一个按钮添加到Box容器中
Box vBox=Box.createHorizontalBox();
vBox.add(new TextField(20));
vBox.add(new Button("确定"));

//把Box容器添加到Dialog中
d1.add(vBox);

//2.通过setBounds方法设置Dialog组件的位置以及大小
d1.setBounds(20,30,300,200);


//3.创建按钮
Button b1=new Button("按钮1:打开模式对话框");


//4.给按钮添加点击后的行为
b1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
d1.setVisible(true);
}
});

//5.把按钮添加到frame中
frame.add(b1,BorderLayout.NORTH);


frame.pack();
frame.setVisible(true);
}
}

3.2.2 FileDiaglog

Dialog类还有一个子类:FileDialog,它代表一个文件对话框,用于打开或者保存文件,需要注意的是FileDialog无法指定模态或者非模态,这是因为FileDialog依赖于运行平台的实现,如果运行平台的文件对话框是模态的,那么FileDialog也是模态的,那么FileDialog也是模态的,否则就是非模态的。

方法名称 方法功能
FileDialog(Frame parent,String title,int mode) 创建一个对话框:parent:指定一个父窗口 title:对话框标题 mode:文件对话框类型,如果指定为FileDialog.LOAD,用于打开文件,如果指定为FileDialog.SAVE,用于保存文件
String getDirectory() 获取被打开或保存文件的绝对路径
String getFile() 获取被打开或保存文件的文件名

案例:

​ 使用Frame、Button、和FileDialog完成下图效果:

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package AWT;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class FileDialogDemo {
public static void main(String[] args){
Frame frame=new Frame("这里是测试FileDialog");

//1.创建两个FileDialog对象
FileDialog f1=new FileDialog(frame,"选择要打开的文件:",FileDialog.LOAD);
FileDialog f2=new FileDialog(frame,"选择要保存的文件:",FileDialog.SAVE);
//2.创建两个按钮
Button b1=new Button("打开文件");
Button b2=new Button("保存文件");
//3.给这两个按钮设置点击后的行为:获取打开或者保存的路径文件名
b1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
f1.setVisible(true);//代码会阻塞到这里

//获取选择的路径以及文件
String directory=f1.getDirectory();
String file=f1.getFile();
System.out.println("打开的文件路径为:"+directory);
System.out.println("打开的文件名:"+file);
}
});
b2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
f2.setVisible(true);//代码会阻塞到这里

//获取选择的路径以及文件
String directory=f2.getDirectory();
String file=f2.getFile();
System.out.println("保存的文件路径为:"+directory);
System.out.println("保存的文件名:"+file);
}
});
//4.把按钮添加到Frame中
frame.add(b1,BorderLayout.NORTH);
frame.add(b2,BorderLayout.SOUTH);


//5.设置frame的最佳大小以及可见
frame.pack();
frame.setVisible(true);

}
}

4.事件处理机制

4.1GUI事件处理机制

定义:

​ 在某个组件上发生操作的时候,会自动触发一段代码的执行。

在GUI事件处理机制中涉及到4个重要的概念需要理解:

事件源:操作发生的场所,通常指某个组件,例如按钮,窗口等。

事件:在事件源上发生的操作可以叫做事件,GUI会把事件都封装到一个Event对象中,如果需要知道该事件的详细信息,就可以通过Event对象来获取。

事件监听器:当在某个事件源上发生了某个对象,事件监听器就可以对这个事件进行处理。

注册监听:把某个事件监听器(A)通过某个事件(B)绑定到某个事件源(C)上,当在事件源C上发生事件B后,那么事件监听器A的代码就会自动执行。

使用步骤:

1.创建事件源组件对象;

2.自定义类,实现xxxListener接口,重写方法;

3.创建事件监听器对象(自定义类对象)

4.调用事件源组件对象的addXxxxListener方法完成注册监听

案例:

​ 完成下图效果,点击确定按钮,在单行文本框内显示hello world

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package AWT;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class EventDemo1 {
Frame frame=new Frame("这里测试事件处理");
TextField tf=new TextField(30);
Button ok=new Button("确认");
public void init(){
//组装视图
//监听器
MyListener myListener=new MyListener();


//注册监听
ok.addActionListener(myListener);
//把tf和ok放到frame中
frame.add(tf,BorderLayout.NORTH);
frame.add(ok);
frame.pack();
frame.setVisible(true);

}
private class MyListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e){
tf.setText("hello world");
}
}
public static void main(String[] args){
new EventDemo1().init();
}

}


4.2GUI常用事件和事件监听器

​ 事件监听器必须实现事件监听器接口,AWT提供了大量的事件监听器接口用于实现不同类型的事件监听器,用于监听不同类型的事件。AWT中提供了丰富的事件类,用于封装不同组件上所发生的特定操作,AWT的事件类都是AWTEvent类的子类,AWTEvent是EventObject的子类。

4.2.1事件

AWT把事件分为了两大类:

​ 1.低级事件:这类事件是基于某个特定动作的事件。比如进入、点击、播放等动作的鼠标事件,再比如得到焦点和失去焦点等焦点事件。

事件 触发时机
ComponentEvent 组件事件,当组件尺寸发生变化,位置发生移动,显示/隐藏状态发生改变时触发该事件
ContainerEvent 容器事件,当容器里发生添加组件、删除组件时触发该事件
WindowEvent 窗口事件,当窗口状态发生改变(如打开、关闭、最大化、最小化)时触发该事件
FocusEvent 焦点事件,当事件得到焦点或者失去焦点时触发该事件
KeyEvent 键盘事件,当按键被按下、松开、单击时触发该事件
MouseEvent 鼠标事件,当进行单击、按下、松开、移动鼠标等动作时触发该事件
PaintEvent 组件绘制事件,该事件是一个特殊的事件类型,当GUI组件

​ 2.高级事件:这类事件不会基于某个特定动作,而是根据功能含义的事件。

事件 触发时机
ActionEvent 动作事件,当按钮、菜单项被单击,在TextField中按Enter键触发
AjustmentEvent 调节事件,在滑动条上移动滑块以调节数值时触发该事件
ItemEvent 选项事件,在用户选中某项,或取消选中某项时触发该事件
TextEvent 文本事件,当文本框、文字域里的文本发生改变时触发该事件

4.2.2事件监听器

不同的事件需要不同的监听器监听,不同的监听器需要实现不同的监听器接口,当指定事件发生后,事件监听器就会调用所包含的事件处理器(实例方法)来处理事件。

事件类别 描述信息 监听器接口名
ContainerEvent 容器中增加或者删除了组件 ContainerListener
TextEvent 文本字段或者文本区发生改变 TextListener
ActionEvent 激活组件 ActionListener
ItemEvent 选择了某些项目 ItemListener
MouseEvent 鼠标移动 MouseMotionListener
MouseEvent 鼠标点击等 MouseListener
KeyEvent 键盘输入 KeyListener
FoucsEvnet 组件收到或者失去焦点 FoucsListener
AdjustmentEvent 移动了滚动条等组件 AdjustListener
ComponentEvent 对象移动缩放显示隐藏等 ComponentListener
WindowEvent 窗口收到窗口级事件 WindowListener

案例一:

​ 通过ContainerListener监听Frame容器添加组件;

​ 通过TextListener监听TextField内容变化;

​ 通过ItemListener监听Choice条目中状态变化;

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package AWT;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ListenerDemo1 {
public static void main(String[] args){
Frame frame=new Frame("这里测试监听器");

//创建组件(事件源)
TextField tf=new TextField(30);
Choice names=new Choice();
names.add("第一");
names.add("第二");
names.add("第三");
names.add("第四");

//给文本域添加TextListener,监听内容的变化
tf.addTextListener(new TextListener() {
@Override
public void textValueChanged(TextEvent e) {
String text=tf.getText();
System.out.println("当前文本框内容为:"+text);
}
});

//给下拉选择框添加ItemListener,监听条目选项的变化
names.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
Object item=e.getItem();
System.out.println("当前选中的条目为:"+item);
}
});

//给frame注册ContainerListener监听器,监听容器中组件的添加
frame.addContainerListener(new ContainerListener() {
@Override
public void componentAdded(ContainerEvent e) {
Component child=e.getChild();
System.out.println("frame中添加了:"+child);
}

@Override
public void componentRemoved(ContainerEvent e) {

}
});

//添加到frame中
Box hBox= Box.createHorizontalBox();
hBox.add(tf);
hBox.add(names);
frame.add(hBox);

//设置frame的最佳大小以及可见
frame.pack();
frame.setVisible(true);
}
}

案例2:

​ 给Frame设置WindowListener,监听用户点击X的动作,如果用户点击X,则关闭当前的窗口

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package AWT;
import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.event.WindowAdapter;

public class ListenerDemo2 {
public static void main(String[] args){
Frame frame=new Frame("这里是测试WindowListener");

frame.addWindowListener(new WindowAdapter() {
public void windowOpened(WindowEvent e) {
System.out.println("打开了Window界面");
}


public void windowClosing(WindowEvent e) {
System.out.println("关闭了Window界面");
System.exit(0);
}

});
frame.setBounds(200,200,500,300);
frame.setVisible(true);
}
}

5.菜单组件

​ 在实际开发中,除了主界面,还有一类比较重要的内容就是菜单相关组件,可以通过菜单相关组件很方便的使用特定的功能,在AWT中,菜单相关组件的使用和之前的组件一模一样,只需要把菜单条、菜单、菜单项组合到一起,按照一定的布局,放入到容器中即可。

下表给出常见的菜单相关组件:

菜单组件名称 功能
MenuBar 菜单条,菜单的容器
Menu 菜单组件,菜单项的容器。它也是MenuItem的子类,所以可以作为菜单项使用
PopupMenu 上下文菜单组件(右键菜单组件)
MenuItem 菜单项选项
CheckboxMenuItem 复选框菜单项组

菜单相关组件使用:

1.准备菜单项组件,这些组件可以是MenuItem及其子类对象

2.准备菜单组件Menu或者PopupMenu(右击弹出子菜单),把第一步中准备好的菜单项组件添加进来

3.准备菜单条组件MenuBar,把第二步中准备好的菜单组件Menu添加进来

4.把第三步中准备好的菜单条组件添加到窗口对象中显示

小技巧:

1.如果要在某个菜单的菜单项之前添加分割线,那么只需要调用Menu的add(new MenuItem(“.”))即可。

2.如果要在某个菜单项关联快捷键功能,那么只需要在创建菜单项对象时设置即可,例如给菜单项关联crtl+shift+Q快捷键,只需要:new MenuItem(“菜单项名字”,new MenuShortcut(KeyEvent.VK_Q,true));

案例:

​ 使用常用awt中常用菜单组件,完成下图效果。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package AWT;
import javax.xml.crypto.dsig.SignatureProperties;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

public class SimpleMenu {
//创建窗口
private Frame frame=new Frame("这里测试菜单相关组件");

//创建菜单条
MenuBar menuBar=new MenuBar();

//创建菜单组件
Menu fileMenu=new Menu("文件");
Menu editMenu=new Menu("编辑");
Menu formatMenu=new Menu("格式");

//菜单项组件
MenuItem auto=new MenuItem("自动换行");
MenuItem copy=new MenuItem("复制");
MenuItem paste=new MenuItem("粘贴");
MenuItem comment=new MenuItem("注释 ",new MenuShortcut(KeyEvent.VK_Q,true));
//关联快捷键 Ctrl+shift+Q
MenuItem cancel=new MenuItem("取消注释");
TextArea ta=new TextArea(6,40);


public void init(){
//组装视图
comment.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ta.append("您点击了菜单项"+e.getActionCommand()+"\n");

}
});

formatMenu.add(comment);
formatMenu.add(cancel);

//组装编译菜单
editMenu.add(auto);
editMenu.add(copy);
editMenu.add(paste);
editMenu.add(formatMenu);

//组装菜单条
menuBar.add(fileMenu);
menuBar.add(editMenu);

//把菜单条放到frame
frame.setMenuBar(menuBar);
frame.add(ta);
//设置frame的最佳大小和可见
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args){
new SimpleMenu().init();
}
}

6.绘图

​ 很多程序例如各种游戏都需要在窗口绘制各种图形,除此之外,即使在开发javaEE项目时,有时候也必须”动态”地向客户端生成各种图形、图表,比如图形验证码、统计图等,这都需要利用AWT的绘图功能。

组件绘图原理:

​ 在AWT中,真正提供绘图功能的对象是Graphics对象。

​ paint(Graphics g):绘制组件的外观;

​ update(Graphics g):内部调用paint方法,刷新组件外观;

​ repaint(Graphics g):调用update方法,刷新组件外观;

一般情况下,update和paint方法是由AWT系统负责调用,如果程序要希望系统程序绘制组件,可以调用repaint方法实现。

Graphics类的使用:

​ AWT中提供了Canvas类充当画布,提供了Graphics类充当画笔,通过调用Graphics对象的setColor()方法可以给画笔设置颜色。

画图的步骤:

​ 1.自定义类,继承Canvas类,重写paint(Graphics g)方法完成画图;

​ 2.在paint方法内部,真正开始画图之前调用Graphics对象的setColor(),setFont()方法设置画笔的颜色、字体等属性;

​ 3.调用画笔的Graphics的drawXxx()方法开始画图。

​ Graphics类的常用方法:

方法名称 方法功能
setColor(Color c) 设置颜色
setFont(Font font) 设置字体
drawLine() 绘制直线
drawRect() 绘制矩形
drawRoundRect() 绘制圆角矩形
drawOval() 绘制椭圆
drawPolygon() 绘制多边形
drawArc() 绘制圆弧
drawPolyLine() 绘制折线
fillRect() 填充矩形区域
fillRoundRect() 填充圆角矩形区域
fillOval() 填充椭圆区域
fillPolygon() 填充多边形区域
fillArc() 填充圆弧对应的扇形区域
drawImage() 绘制位图

案例:

​ 使用AWT绘图,绘制下图效果:

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package AWT;
import java.awt.*;
import java.awt.event.*;
public class simpleDraw {
private final String RECT_SHAPE = "rect";
private final String OVAL_SHAPE = "oval";
private Frame frame = new Frame("绘制图形");
Button butRect = new Button("绘制矩形");
Button butOval = new Button("绘制椭圆");
//定义一个变量,记录当前绘制的图形
private String shape = "";
//自定义类继承Canvas类,从写paint方放完成画图
private class MyCanvas extends Canvas {
@Override
public void paint(Graphics g) {
//绘制不同的图形
if (shape.equals(RECT_SHAPE)) {
//矩形
g.setColor(Color.BLACK);
g.drawRect(100, 100, 150, 100);

} else if (shape.equals(OVAL_SHAPE)) {
//圆形
g.setColor(Color.RED);
g.drawOval(100, 100, 150, 100);
}

}
}
//创建自定义画布
MyCanvas drawArea =new MyCanvas();
public void init(){
//组装视图
butRect.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//修改记录值为rect
shape=RECT_SHAPE;
drawArea.repaint();
}
});
butOval.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//修改记录值为oval
shape=OVAL_SHAPE;
drawArea.repaint();
}
});
//创建panel承载按钮
Panel panel = new Panel();
panel.add(butRect);
panel.add(butOval);
frame.add(panel,BorderLayout.SOUTH);
drawArea.setPreferredSize(new Dimension(300,300));
frame.add(drawArea);
frame.pack();
frame.setVisible(true);

}

public static void main(String[] args) {
new simpleDraw().init();
}
}

位图: Graphics提供了drawImage方法来绘制位图,该方法需要一个image参数,通过该方法可以绘制出指定的位图

使用步骤:

​ 1.创建image的子类对象BufferedImage(int width,int height,int ImageType),创建时需要指定位图的宽高以及类型属性;此时相当于在内存中生成了一张照片

​ 2.调用BufferedImage对象的getGraphics()方法获取画笔,此时就可以往内存中的这张图片上绘图了,绘图的方法和之前的学习一模一样

​ 3.调用组件paint()方法中提供的Graphics对象的drawImage()方法,一次性的内存中的图片BufferedImage绘制到特定的组件上去。

使用位图绘制的好处:

​ 使用位图来绘制组件,相当于实现了图的缓冲区,此时绘图中没有直接把图形绘制到组件,而是先绘制到内存中的BufferedImage上,等全部绘制完成后,再一次性的图像显示到组件上即可,这样用户的体验会好一些。

案例:

​ 通过BufferedImage实现一个简单的手绘程序,通过鼠标能够在窗口中绘图。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package AWT;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;

public class HandDraw {
Frame frame = new Frame("HandDraw");
//定义画图区域的宽高
private final int AREA_WIDTH = 500;
private final int AREA_HEIGHT = 400;
//定义右击菜单,设置画笔的color
private PopupMenu colorMenu = new PopupMenu();
private MenuItem redItem = new MenuItem("red");
private MenuItem greenItem = new MenuItem("green");
private MenuItem blueItem = new MenuItem("blue");
//定义一个变量定义,记录当前画笔的颜色
private Color foceColor = Color.black;
//创建一个位图对象
BufferedImage image = new BufferedImage(AREA_WIDTH,AREA_HEIGHT,BufferedImage.TYPE_INT_RGB);
//通过位图获取关联的Graphics对象
Graphics g = image.getGraphics();

//自定义一个类 继承Canvas
private class MyCanvas extends Canvas {
@Override
public void paint(Graphics g) {
g.drawImage(image, 0, 0, null);
}
}
MyCanvas drawArea = new MyCanvas();
//定义变量,记录鼠标拖动过程中上一处的坐标
private int preX=-1;
private int preY=-1;
public void init() {
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
switch (actionCommand) {
case "red":
foceColor = Color.RED;
break;
case "green":
foceColor = Color.GREEN;
break;
case "blue":
foceColor = Color.BLUE;
break;
}
}
};
redItem.addActionListener(listener);
greenItem.addActionListener(listener);
blueItem.addActionListener(listener);

colorMenu.add(redItem);
colorMenu.add(greenItem);
colorMenu.add(blueItem);
//把colorMenu设置绘图区域
drawArea.add(colorMenu);

drawArea.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
boolean popupTrigger = e.isPopupTrigger();
if (popupTrigger){
colorMenu.show(drawArea,e.getX(),e.getY());
}
//重置
preX=-1;
preY=-1;
}
});
// 设置位图的背景色
g.setColor(Color.white);
g.fillRect(0,0,AREA_WIDTH,AREA_HEIGHT);
//鼠标点击移动事件
drawArea.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
if (preX>0&&preY>0){
g.setColor(foceColor);
g.drawLine(preX,preY,e.getX(),e.getY());
}
//修正preX值和preY的值
preX=e.getX();
preY=e.getY();
//重绘组件
drawArea.repaint();
}
});
drawArea.setPreferredSize(new Dimension(AREA_WIDTH,AREA_HEIGHT));
frame.add(drawArea);
//组装视图
frame.setVisible(true);
frame.pack();

}

public static void main(String[] args) {
new HandDraw().init();
}
}

ImageIO的使用

​ 在实际生活中,很多软件都支持打开本地磁盘已经保存的图片,然后点击进行编辑,编译完成后,再重新保存到本地磁盘。如使用AWT要完成这样的功能,那么需要用到ImageIO这个类,可以操作本地磁盘的图片文件。

方法名称 方法功能
static BufferedImage read(File input) 读取本地磁盘图片文件
static BufferedImage read(InputStream input) 读取本地磁盘图片文件
static boolean write(RenderedImage im,String formatName,File output) 往本地磁盘中输出图片

案例:

​ 编写图片查看程序,支持另存操作

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package AWT;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ReadAndSaveImage {
private Frame frame = new Frame("图片查看器");

MenuBar menuBar = new MenuBar();
Menu menu = new Menu("文件");
MenuItem open = new MenuItem("打开");

MenuItem save = new MenuItem("另存为");

//声明BufferedImage对象,记录本地存取到内存中的图片
BufferedImage image ;
private class MyCanvas extends Canvas{
@Override
public void paint(Graphics g) {
g.drawImage(image,0,0,null);
}
}
MyCanvas drawArea = new MyCanvas();

public void init() throws Exception{

//组装视图
open.addActionListener(e -> {
//打开一个文件框
FileDialog fileDialog = new FileDialog(frame,"打开图片",FileDialog.LOAD);
fileDialog.setVisible(true);

//获取用户选择的图片路径以及名称
String dir = fileDialog.getDirectory();
String fileName = fileDialog.getName();
try {
image = ImageIO.read(new File(dir,fileName));
drawArea.repaint();
}catch(IOException ex){
ex.printStackTrace();
}
});
save.addActionListener(e -> {
//展示一个文件对话框
FileDialog fileDialog = new FileDialog(frame,"保存图片",FileDialog.SAVE);
fileDialog.setVisible(true);

//获取用户选择的图片路径以及名称
String dir = fileDialog.getDirectory();
String fileName = fileDialog.getName();
try {
ImageIO.write(image,"JPEG",new File(dir,fileName));
}catch(IOException ex){
ex.printStackTrace();
}
});
menu.add(open);
menu.add(save);
menuBar.add(menu);
//把菜单条放入到窗口中
frame.setMenuBar(menuBar);
frame.add(drawArea);
frame.setBounds(200,200,1080,1080);

frame.setVisible(true);

frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});


}
public static void main(String arg[]) throws Exception{
new ReadAndSaveImage().init();
}

}

二、Swing编程

1.概述

​ Swing是纯100%Java实现的,不再依赖于本地平台的GUI,因此可以在所有平台上都保持相同的界面外观。独立于本地平台的Swing组件被称为轻量级组件,而依赖于本地平台的AWT组件被称为重量级组件

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

使用Swing的优势

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

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

​ 3.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组件总是具有和本地平台相同的外观。

2.基本组件的用法

2.1、Swing组件层次

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

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

  • JComboBox:对应于AWT里的Choice组件,但比Choice组件功能更丰富;
  • JFileChooser:对应于AWT里的FileDialog组件;
  • JScrollBar:对应于AWT里的ScrollBar组件,注意两个组件类名中b字母的大小写差别;
  • JCheckBox:对应于AWT里的Checkbox组件,注意两个组件类名中b字母的大小写差别;
  • JCheckBoxMenuItem:对应于AWT里的CheckboxMenuItem组件,注意两个组件类名中b字母的大小写差别。

Swing组件按照功能来分类:

  • 顶层容器:JFrame、JApplet、JDialog和JWindow。
  • 中间容器:JPanel、JScrollPane、JSplitPane、JToolBar等。
  • 特殊容器:在用户界面上具有特殊作用的中间容器,如JInternalFrame、JRootPane、JLayeredPane和JDesktopPane等。
  • 基本组件:实现人机交互的组件,如JButton、JComboBox、JList、JMenu、JSlider等。
  • 不可编辑信息的显示组件:向用户显示不可编辑信息的组件,如JLabel、JProgressBar和JToolTip等。
  • 可编辑信息的显示组件:向用户显示能被编辑的格式化信息的组件,如JTable、JTextArea和JTextField等。
  • 特殊对话框组件:可以直接产生特殊对话框的组件,如JColorChooser和JFileChooser等。

2.2AWT组件的Swing实现

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

  1. 可以为Swing组件设置提示信息。使用setToolTipText()方法,为组件设置对用户有帮助的提示信息。
  2. 很多Swing组件如按钮、标签、菜单项等,除使用文字外,还可以使用图标修饰自己。为了允许在Swing组件中使用图标,Swing为Icon接口提供了一个实现类:ImageIcon,该实现类代表一个图像图标。
  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实现。

上一篇:
字符串
下一篇:
C++STL容器