GUI编程的基础AWT。

体系

容器

image

Panel不能独立存在,必须存在于其他容器中,默认使用FlowLayout布局管理器
ScrollPane是一个带滚动条的容器,当组件占用空间过大时自动产生滚动条,也可以指定默认具有滚动条,同样不能单独存在,默认使用BorderLayout布局管理器,且通常不允许改变(因为通常用于装其他组件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.swing.*;
import java.awt.*;

/**
* @author YL
* @date 2018/6/21 11:12
*/
public class DivisionFrame {
public static void main(String[] args) {
Frame f = new Frame("测试窗口");
ScrollPane sp = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS);
sp.add(new TextField(20));
sp.add(new JButton("确定"));
f.add(sp);
f.setBounds(30, 30, 250, 120);
f.setVisible(true);
}
}

布局管理器

 所有AWT容器都有默认的布局管理器,也可以使用容器对象的setLayout(LayoutManger lm)方法来修改。

FlowLayout布局管理器

 当读者在电脑上输入一篇文章时,所使用的就是FlowLayout布局管理器,所有的文字默认从左向右排列,遇到边界就会折回下一行重新开始。AWT中的FlowLayout布局管理器与此完全类似,只是此时排列的是AWT组件,而不是文字。

 FlowLayout([int align],[int hgap,int vgap]),三个参数依次代表为:设置组件的排列方向(从左向右、从右向左、从中间向两边),垂直间距,水平间距。期中第一个参数使用FlowLayout类的静态常量:FlowLayoutLEFT、FlowLayout.CENTER、FlowLayout.RIGHT。

int hgap, int vgap参数要同时出现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.swing.*;
import java.awt.*;

/**
* @author YL
* @date 2018/6/21 11:12
*/
public class DivisionFrame {
public static void main(String[] args) {
Frame f = new Frame("测试窗口");
f.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 5));
for (int i = 0; i < 10; i++) {
f.add(new JButton("按钮" + i));
}
//pack()方法是Windows容器提供的方法,用于将窗口调整到最佳大小
f.pack();
f.setVisible(true);
}
}

BorderLayout布局管理器

 BorderLayout将容器分为east,west,north,center五个区域。当向容器中添加组件时默认为添加在中间,向同一个区域添加会使得组件被覆盖,当添加的组件少于五个时,旁边的组件会自动占据空白位置。

 BorderLayout([int hgap,int vgap])。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import javax.swing.*;
import java.awt.*;

import static java.awt.BorderLayout.*;//静态导入

/**
* @author YL
* @date 2018/6/21 11:12
*/
public class DivisionFrame {
public static void main(String[] args) {
Frame f = new Frame("测试窗口");
f.setLayout(new BorderLayout(30,5));
f.add(new JButton("中"),CENTER);
f.add(new JButton("南"),SOUTH);
f.add(new JButton("北"),NORTH);
f.add(new JButton("西"),WEST);
f.add(new JButton("东"),EAST);
//pack()方法是Windows容器提供的方法,用于将窗口调整到最佳大小
f.pack();
f.setVisible(true);
}
}

 BorderLayout布局只能添加五个组件,但是可以在组件中包含容器,例如Panel容器,并在容器中添加更多组件。

GridLayout布局管理器

 GridLayout布局管理器将容器分割成纵横线分隔的网格,每个网格所占的区域大小相同。当向使用 GridLayout布局管理器的容器中添加组件时,默认从左向右、从上向下依次添加到每个网格中。与 FlowLayout不同的是,放置在GridLayout布局管理器中的各组件的大小由组件所处的区域来决定(每个组件将自动占满整个区域)。以FlowLayout的代码为例,原代码的窗口变大后按钮大小不会变化,而使用GridLayout布局管理器会使得按钮大小变化,使各组件占满Frame。

 GridLayout(int rows,int cols,[int hgap,int vgap]):指定行数和列数或者同时指定出间距。

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
import javax.swing.*;
import java.awt.*;

import static java.awt.BorderLayout.NORTH;

/**
* @author YL
* @date 2018/6/21 11:12
*/
public class DivisionFrame {
public static void main(String[] args) {
Frame f = new Frame("计算器");
Panel p1 = new Panel();
p1.add(new TextField(30));
f.add(p1,NORTH);
Panel p2 = new Panel();
p2.setLayout(new GridLayout(3, 5, 4, 4));
String[] buttonName = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "-", "*", "/"};
for (int i = 0; i < buttonName.length; i++) {
p2.add(new JButton(buttonName[i]));
}
f.add(p2);
f.pack();
f.setVisible(true);
}
}

GridBagLayout布局管理器

 GridBagLayout布局管理器是最灵活的,在该布局管理器中,有个组件可以跨越一个或多个网格,可以设置网格的大小。在窗口大小发生变化时,也可以更精确控制窗口各部分的拉伸。为了达到这种精确的控制,该布局管理器使用一个GridBagConstraints(网格包约束)对象。具体方式是,先创建GridBagLayout布局管理器对象,并将某个容器设置为该管理器,随后创建GridBagConstraints对象并指定一些相关属性,然后用GridBagLayout对象的setConstrains方法将GridBagConstraints对象与某个组件关联。简而言之,创建一个针对具体组件的“约束”。GridBagConstraints的具体属性如下:

  • gridx、gridy:设置受该对象控制的GUI组件左上角所在网格的横向索引、纵向索引 (GridBagLayout左上角网格的索引为0、0)。这两个值还可以是GridBagConstraints.RELATIVE (默认值),它表明当前组件紧跟在上一个组件之后。(索引即位置)

  • gridwidth、gridheight:设置受该对象控制的GUI组件横向、纵向跨越多少个网格,两个属性值的默认值都是1。如果设置这两个属性值为GridBagConstraints.REMAINDER,这表明受该对象控制 的GUI组件是横向、纵向最后一个组件;如果设置这两个属性值为GridBagConstraints. RELATIVE, 这表明受该对象控制的GUI组件是横向、纵向倒数第二个组件。

  • fill:设置受该对象控制的GUI组件如何占据空白区域。该属性的取值如下。

    • GridBagConstraints.NONE: GUI 组件不扩大。

    • GridBagConstraints.HORIZONTAL: GUI组件水平扩大以占据空白区域。

    • GridBagConstraints.VERTICAL: GUI组件垂直扩大以占据空白区域。

    • GridBagConstraints.BOTH: GUI组件水平、垂直同时扩大以占据空白区

  • ipadx、ipady:设置受该对象控制的GUI组件横向、纵向内部填充的大小,即在该组件最小尺寸的基础上还需要增大多少。如果设置了这两个属性,则组件横向大小为最小宽度再加ipadx*2像素,纵向大小为最小高度再加ipady*2像素。

  • insets:设置受该对象控制的GUI组件的外部填充的大小,即该组件边界和显示区域边界之间的 距离。

  • anchor:设置受该对象控制的GUI组件在其显示区域中的定位方式。定位方式如下。

    • GridBagConstraints.CENTER (中间)
    • GridBagConstraints.NORTH (上中)
    • GridBagConstraints.NORTHWEST(左上角)
    • GridBagConstraints.NORTHEAST(右上角)
    • GridBagConstraints.SOUTH (下中)
    • GridBagConstraints.SOUTHEAST(右下角)
    • GridBagConstraints.SOUTHWEST(左下角)
    • GridBagConstraints.EAST(右中)
    • GridBagConstraints.WEST(左中)
  • weightx, weighty:设置受该对象控制的GUI组件占据多余空间的水平、垂直增加比例(也叫权重,即weight的直译),这两个属性的默认值是0 , 即该组件不占据多余空间。假设某个容器的水平线上包括三个GUI组件,它们的水平增加比例分别是1、2、3 ,但容器宽度增加60像素时,则第一个组件宽度增加10像素,第二个组件宽度增加20像素,第三个组件宽度增加30像素。如果其增加比例为0 , 则表示不会增加。

 如果希望某个组件的大小随容器的增大而增大,则必须同时设置控制该组件的GridBagConstraints 对象的fill属性和weightx、weighty属性。

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
import javax.swing.*;
import java.awt.*;

/**
* @author YL
* @date 2018/7/16 16:40
*/
public class GridBagTest {
private Frame f = new Frame("测试窗口");
private GridBagLayout gb = new GridBagLayout();
private GridBagConstraints gbc = new GridBagConstraints();
private JButton[] bs = new JButton[10];

public void init() {
f.setLayout(gb);
for (int i = 0; i < bs.length; i++) {
bs[i] = new JButton("按钮" + i);
}
// 首先设置占据空白区域方式,所有组件都一样,没有改
gbc.fill = GridBagConstraints.BOTH;
// 设置水平大小增加比例,0,1,2,3四个按钮比例是1:1:1:1
gbc.weightx = 1;
addButton(bs[0]);
addButton(bs[1]);
addButton(bs[2]);
// 3为第一行最后一个
gbc.gridwidth = GridBagConstraints.REMAINDER;
addButton(bs[3]);

// 4原本是不按比例增加,但是因为设置的填充方式,会把整行占满
gbc.weightx = 0;
addButton(bs[4]);

gbc.gridwidth = 2;
addButton(bs[5]);
// 这里发现把数值改来改去出来的都不会变
gbc.gridwidth = 1;
gbc.gridheight = 2;
gbc.gridwidth = GridBagConstraints.REMAINDER;
addButton(bs[6]);

gbc.gridwidth = 1;
gbc.gridheight = 2;
gbc.weighty = 1;
addButton(bs[7]);

gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.gridheight = 1;
addButton(bs[8]);
addButton(bs[9]);
f.pack();
f.setVisible(true);
}

private void addButton(JButton b) {
gb.setConstraints(b, gbc);
f.add(b);
}

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

 这段代码的注释写着写着就不想写了,因为发现这个布局真的很烦,明明指定的效果却会因为其他一些不说清的因素而不变。。。反正也不重要,鸽了。

CardLayout布局管理器

 CardLayout布局管理器以时间而非空间来管理它里面的组件,它将加入容器的所有组件看成一叠卡片,每次只有最上面的那个Component才可见。就好像一副扑克牌,它们叠在一起,每次只有最上面的一张扑克牌才可见。

 CardLayout([int hgap,int vgap])

CardLayout用于控制组件可见的5 个常用方法如下。

  • first(Container target):显示 target 容器中的第一张卡片。
  • last(Container target):显示target容器中的最后一张卡片。
  • previous(Container target):显示target容器中的前一张卡片。
  • next(Container target):显示target容器中的后一张卡片。
  • show(Container target,String name):显示target容器中指定名字

绝对定位

 也可以指定布局管理器为null,然后使用setBounds或setSize方法来控制具体组件的大小,位置。但是这样不利于跨平台。

BoxLayout布局管理器

 BoxLayout布局管理器是Swing新引入的一个布局管理器,相较于GridBagLayout,它比较简单,但是功能却没有减少。BoxLayout只提供了一个很简单的构造器:

 BoxLayout(Container target, int axis):指定创建基于target容器的BoxLayout布局管理器,该布 局管理器里的组件按axis方向排列。其中axisBoxLayout.X_AXIS(横向)和BoxLayout.Y_AXIS (纵向)两个方向。

 BoxLayout布局管理器通常和Box容器结合使用,它属于Swing。它有点像Panel,默认使用BoxLayout。Box提供了如下两个静态方法来创建Box对象:

  • createHorizontalBox(): 创建一个水平排列组件的Box容器。

 * createHorizontalBox(): 创建一个水平排列组件的Box容器。

  • createVerticalBox(): 创建一个垂直排列组件的Box容器。

 但是这两个方法创建的容器是不具有间距的,全部挤在一起。对于间距,Box提供了相关的方法来创建:

  • createHorizontalGlue(): 创建一条水平Glue (可在两个方向上同时拉伸的间距)
  • createVerticalGlue(): 创建一条垂直Glue (可在两个方向上同时拉伸的间距)
  • createHorizontalStrut(int width):创建一条指定宽度的水平Strut (可在垂直方向上拉伸的间距)
  • createVerticalStrut(int height):创建一条指定高度的垂直Strut (可在水平方向上拉伸的间距)
  • createRigidArea(Dimension d):创建指定宽度、高度的RigidArea (不可拉伸的间距)

 这意味着在Box中空白间距也是一种组件。

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
import javax.swing.*;
import java.awt.*;

/**
* @author YL
* @date 2018/7/17 14:54
*/
public class BoxSpaceTest {
private Frame f = new Frame("测试窗口?");
/**
* horizontal Box
*/
private Box horizontal = Box.createHorizontalBox();
/**
* vertical Box
*/
private Box vertical = Box.createVerticalBox();

public void init() {
horizontal.add(new Button("水平按钮1"));
horizontal.add(Box.createHorizontalGlue());
horizontal.add(new Button("水平按钮2"));
horizontal.add(Box.createHorizontalStrut(10));
horizontal.add(new Button("水平按钮3"));
vertical.add(new Button("垂直按钮1"));
vertical.add(Box.createVerticalGlue());
vertical.add(new Button("垂直按钮2"));
vertical.add(Box.createVerticalStrut(10));
vertical.add(new Button("垂直按钮3"));
f.add(horizontal, BorderLayout.NORTH);
f.add(vertical);
f.pack();
f.setVisible(true);
}

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

 注意,这里的按钮用的是JButton,窗口拉伸后按钮大小不变,而用Button时会自动填充。

AWT常用组件

基本组件

 AWT提供了如下基本组件。

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

对话框

 Dialog是Window类的子类,是一个容器类,属于特殊组件。对话框是可以独立存在的顶级窗口, 因此用法与普通窗口的用法几乎完全一样。但对话框有如下两点需要注意。

  • 对话框通常依赖于其他窗口,就是通常有一个parent窗口。
  • 对话框有非模式(non-modal)和模式(modal)两种,当某个模式对话框被打开之后,该模式对话框总是位于它依赖的窗口之上;在模式对话框被关闭之前,它依赖的窗口无法获得焦点,

 对话框有多个重载的构造器,它的构造器可能有如下三个参数:

  • owner:指定该对话框所依赖的窗口,既可以是窗口,也可以是对话框。
  • title:指定该对话框的窗口标题。
  • modal:指定该对话框是否是模式的,可以是true或false。

 下面的代码创建了模式对话框和非模式对话框:

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
import javax.swing.*;
import java.awt.*;

/**
* @author YL
* @date 2018/7/17 16:52
*/
public class DialogTest {
Frame f = new Frame("测试窗口");
Dialog d1 = new Dialog(f, "模式对话框", true);
Dialog d2 = new Dialog(f, "非模式对话框", false);
JButton b1 = new JButton("打开模式对话框");
JButton b2 = new JButton("打开非模式对话框");

public void init() {
d1.setBounds(20, 30, 400, 400);
d2.setBounds(20, 30, 400, 400);
b1.addActionListener(e -> d1.setVisible(true));
b2.addActionListener(e -> d2.setVisible(true));
f.add(b1);
f.add(b2, BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
}

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

 从动作监听器那里可以看出,两种窗口不是在点击按钮时创建,而是在那时显示出来。

不管是模式对话框还是非模式对话框,打开后都无法关闭它们,因为程序没有为这两个对话框编写事件监听器。还有,如果主程序需要对话框里接收的输入值,则应该把该对话框设置成模式对话框,因为模式对话框会阻塞该程序;如果把对话框设置成非模式对话框,则可能造成对话框被打开了 ,但用户并没有操作该对话框,也没有向对话框里进行输 入,这就会引起主程序的异常。

 Dialog类还有一个子类:FileDialog,它代表一个文件对话框,用于打开或者保存文件。FileDialog
也提供了几个构造器,可分别支持parent、title和 mode三个构造参数,其中parent、title指定文件对话框的所属父窗口和标题;而mode指定该窗口用于打开文件或保存文件,该参数支持如下两个参数值: FileDialog.LOAD、FileDialog.SAVE。FileDialog不能指定是模式对话框还是非模式对话框,这依赖于运行平台。FileDialog还提供了两个方法分别用于获取被打开/保存的文件的绝对路径和文件名:getDirectory(),getFile()。

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 javax.swing.*;
import java.awt.*;

/**
* @author YL
* @date 2018/7/17 22:02
*/
public class FileDialogTest {
Frame f = new Frame("测试窗口");
FileDialog d1 = new FileDialog(f, "选择需要打开的文件", FileDialog.LOAD);
FileDialog d2 = new FileDialog(f, "选择需要保存的文件", FileDialog.SAVE);
JButton b1 = new JButton("打开文件");
JButton b2 = new JButton("保存文件");

public void init() {
b1.addActionListener(e -> {
d1.setVisible(true);
System.out.println(d1.getDirectory() + "\n" + d1.getFile());
});
b2.addActionListener(e -> {
d1.setVisible(true);
System.out.println(d1.getDirectory() + "\n" + d1.getFile());
});
f.add(b1, BorderLayout.NORTH);
f.add(b2, BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
}

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