Java使用AWT和Swing相关的类可以完成图形化界面编程,其中AWT的全称是抽象窗口工具集(Abstract Window Toolkit),它是sun公司最早提供的GUI库,这个GUI库提供了一些基本功能,但这个GUI库的功能比较有限,所以后来sun公司又提供了Swing库。通过使用AWT和Swing提供的图形化界面组件库,java的图形化界面编程非常简单,程序只需要依次创建所需的图形组件,并以合适的方式将这些组件组织在一起,就可以开发出非常美观的用户界面。
当 JDK 1.0发布时, Sun 提供了 一套基本的GUI类库,这个GUI类库希望可以在所有平台下都能运行 ,这套基本类库被称为"抽象窗口工具集 CAbstract Window Toolkit )",它为Java应用程序提供了基本的图形组件 。 AWT是窗口框架,它从不同平台的窗口系统中抽取出共同组件 , 当程序运行时,将这些组件的创建和动作委托给程序所在的运行平台 。 简而言之 ,当使用 AWT 编写图形界面应用时, 程序仅指定了界面组件的位置和行为,并未提供真正的实现,JVM调用操作系统本地的图形界面来创建和平台 一致的对等体 。
使用AWT创建的图形界面应用和所在的运行平台有相同的界面风格 , 比如在 Windows 操作系统上,它就表现出 Windows 风格 ; 在 UNIX 操作系统上,它就表现出UNIX 风格 。 Sun 希望采用这种方式来实现 " Write Once, Run Anywhere " 的目标 。
所有和 AWT 编程相关的类都放在 java.awt 包以及它的子包中, AWT 编程中有两个基类:Component
和 MenuComponent
。
Component
:代表一个能以图形化方式显示出来,并可与用户交互的对象,例如 Button
代表一个按钮,TextField
代表 一个文本框等;MenuComponent
:则代表图形界面的菜单组件,包括 MenuBar
(菜单条)、 Menultem
(菜单项)等子类。其中 Container
是一种特殊的 Component
,它代表一种容器,可以装载普通的 Component
。
AWT中还有一个非常重要的接口叫LayoutManager
,如果一个容器中有多个组件,那么容器就需要使用LayoutManager
来管理这些组件的布局方式。
Window
:是可以独立存在的顶级窗口,默认使用BorderLayout
管理其内部组件布局;Panel
:可以容纳其他组件,但不能独立存在,它必须内嵌其他容器中使用,默认使用FlowLayout
管理其内部组件布局;ScrollPane
:是一个带滚动条的容器,它也不能独立存在,默认使用 BorderLayout
管理其内部组件布局;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(): |
返回该容器内的所有组件 。 |
public class FrameDemo {
public static void main(String[] args) {
// 创建窗口
Frame frame = new Frame("这是窗口名称");
// 设置窗口大小和位置
frame.setBounds(100,100,400,400);
// 设置窗口可见
frame.setVisible(true);
}
}
public class PanelDemo {
public static void main(String[] args) {
// 创建窗口
Frame frame = new Frame("这是窗口名称");
// 设置窗口大小和位置
frame.setBounds(100,100,400,400);
// 创建面板
Panel panel = new Panel();
// 设置面板颜色
panel.setBackground(Color.red);
// 添加组件
panel.add(new Label("密码"));
// 添加组件
panel.add(new TextField(20));
// 添加面板到窗口
frame.add(panel);
// 设置窗口可见
frame.setVisible(true);
}
}
public class ScrollPanelDemo {
public static void main(String[] args) {
Frame frame = new Frame("ScrollPanelDemo");
frame.setBounds(100,100,200,200);
// 创建滚动面板,并指定默认开启滚动条
ScrollPane scrollPane = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS);
scrollPane.add(new TextField("你好 AWT !"));
frame.add(scrollPane);
frame.setVisible(true);
}
}
之前,我们介绍了Component
中有一个方法 setBounds()
可以设置当前容器的位置和大小,但是我们需要明确一件事,如果我们手动的为组件设置位置和大小的话,就会造成程序的不通用性,例如
Label label = new Label("你好,世界");
创建了一个lable组件,很多情况下,我们需要让lable组件的宽高和“你好,世界”这个字符串自身的宽高一致,这种大小称为最佳大小。由于操作系统存在差异,例如在windows上,我们要达到这样的效果,需要把该Lable组件的宽和高分别设置为100px,20px
,但是在Linux操作系统上,可能需要把Lable组件的宽和高分别设置为120px,24px
,才能达到同样的效果。
为了解决这个问题,Java提供了LayoutManager
布局管理器,可以根据运行平台来自动调整组件大小,程序员不用再手动设置组件的大小和位置了,只需要为容器选择合适的布局管理器即可。
在 FlowLayout 布局管理器中,组件像水流一样向某方向流动 (排列) ,遇到障碍(边界)就折回,重头开始排列 。在默认情况下, FlowLayout
布局管理器从左向右排列所有组件,遇到边界就会折回下一行重新开始。
构造方法 | 方法功能 |
---|---|
FlowLayout() |
使用默认的对齐方式及默认的垂直间距、水平间距创建 FlowLayout 布局管理器。 |
FlowLayout(int align) |
使用指定的对齐方式及默认的垂直间距、水平间距创建 FlowLayout 布局管理器。 |
FlowLayout(int align,int hgap,int vgap) |
使用指定的对齐方式及指定的垂直问距、水平间距创建FlowLayout 布局管理器。 |
align
:参数应该使用FlowLayout类的静态常量 : FlowLayout. LEFT
、 FlowLayout. CENTER
、 FlowLayout. RIGHT
,默认是左对齐。
hgap/vgap
:组件中间距通过整数设置,单位是像素,默认是5个像素。
public class FlowLayoutDemo {
public static void main(String[] args) {
Frame frame = new Frame("FlowLayoutDemo");
frame.setBounds(100,100,400,200);
// 设置流式布局,从左到右排列,并设置左右间距为2,上下间距为2
frame.setLayout(new FlowLayout(FlowLayout.LEFT,2,2));
for (int i = 0; i < 10; i++){
frame.add(new Button("按钮"+i));
}
frame.setVisible(true);
}
}
BorderLayout 将容器分为 EAST
、 SOUTH
、 WEST
、 NORTH
、 CENTER
五个区域,普通组件可以被放置在这 5 个区域的任意一个中 。
当改变使用 BorderLayout 的容器大小时, NORTH
、 SOUTH
和 CENTER
区域水平调整,而 EAST
、 WEST
和 CENTER
区域垂直调整。使用BorderLayout 有如下两个注意点:
构造方法 | 方法功能 |
---|---|
BorderLayout() |
使用默认的水平间距、垂直 间距创建 BorderLayout 布局管理器 。 |
BorderLayout(int hgap,int vgap): |
使用指定的水平间距、垂直间距创建 BorderLayout 布局管理器。 |
public class BorderLayoutDemo {
public static void main(String[] args) {
Frame frame = new Frame("BorderLayoutDemo");
frame.setBounds(100,100,300,300);
// 设置边界布局,并设置左右间距为2,上下间距为2
frame.setLayout(new BorderLayout(2,2));
frame.add(new Button("NORTH"),BorderLayout.NORTH);
frame.add(new Button("SOUTH"),BorderLayout.SOUTH);
frame.add(new Button("EAST"),BorderLayout.EAST);
frame.add(new Button("WEST"),BorderLayout.WEST);
frame.add(new Button("CENTER"),BorderLayout.CENTER);
frame.setVisible(true);
}
}
GridLayout 布局管理器将容器分割成纵横线分隔的网格 , 每个网格所占的区域大小相同。当向使用 GridLayout 布局管理器的容器中添加组件时, 默认从左向右、 从上向下依次添加到每个网格中 。
与 FlowLayout不同的是,放置在 GridLayout 布局管理器中的各组件的大小由组件所处的区域决定(每 个组件将自动占满整个区域) 。
构造方法 | 方法功能 |
---|---|
GridLayout(int rows,in t cols) |
采用指定的行数、列数,以及默认的横向间距、纵向间距将容器分割成多个网格 |
GridLayout(int rows,int cols,int hgap,int vgap) |
采用指定的行数、列数 ,以及指定的横向间距 、 纵向间距将容器分割成多个网格。 |
public class GridLayoutDemo {
public static void main(String[] args) {
Frame frame = new Frame("GridLayoutDemo");
frame.setBounds(100,100,200,300);
Panel top = new Panel();
top.add(new TextField(25));
Panel bottom = new Panel();
bottom.setLayout(new GridLayout(5,3));
bottom.add(new Button("+"));
bottom.add(new Button("-"));
bottom.add(new Button("*"));
for (int i = 0; i < 10; i++){
bottom.add(new Button("" + i));
}
bottom.add(new Button("="));
frame.add(top, BorderLayout.NORTH);
frame.add(bottom, BorderLayout.CENTER);
frame.setVisible(true);
}
}
GridBagLayout 布局管理器的功能最强大,但也最复杂,与 GridLayout 布局管理器不同的是,在GridBagLayout 布局管理器中,一个组件可以跨越一个或多个网格,并可以设置各网格的大小互不相同,从而增加了布局的灵活性。当窗口的大小发生变化时,GridBagLayout 布局管理器也可以准确地控制窗口各部分的拉伸 。
由于在GridBagLayout 布局中,每个组件可以占用多个网格,此时,我们往容器中添加组件的时候,就需要具体的控制每个组件占用多少个网格,java提供的GridBagConstaints
类,与特定的组件绑定,可以完成具体大小和跨越性的设置。
GridBagConstraints 属性如下:
属性 | 含义 |
---|---|
gridx |
设置受该对象控制的GUI组件左上角所在网格的横向索引 |
gridy |
设置受该对象控制的GUI组件左上角所在网格的纵向索引 |
gridwidth |
设置受该对象控制的 GUI 组件横向跨越多少个网格GridBagContraints.REMAINDER :表明当前组件是横向最后一个组件GridBagConstraints.RELATIVE :表明当前组件是横向倒数第二个组件。 |
gridheight |
设置受该对象控制的 GUI 组件纵向跨越多少个网格GridBagContraints.REMAINDER :表明当前组件是纵向最后一个组件GridBagConstraints.RELATIVE :表明当前组件是纵向倒数第二个组件。 |
fill |
当"显示区域"大于"组件"的时候,如何调整组件 :GridBagConstraints.NONE :GUI 组件不扩大GridBagConstraints.HORIZONTAL :GUI 组件水平扩大 以 占据空白区域GridBagConstraints.VERTICAL :GUI 组件垂直扩大以占据空白区域GridBagConstraints.BOTH :GUI 组件水平 、 垂直同时扩大以占据空白区域. |
ipadx |
设置受该对象控制的 GUI 组件横向内部填充的大小,即在该组件最小尺寸的基础上还需要增大多少. |
ipady |
设置受该对象控制的 GUI 组件纵向内部填充的大小,即在该组件最小尺寸的基础上还需要增大多少. |
insets |
设置受该对象控制 的 GUI 组件的外部填充的大小 , 即该组件边界和显示区域边界之间的距离 . |
weightx |
设置受该对象控制 的 GUI 组件占据多余空间的水平比例, 假设某个容器的水平线上包括三个 GUI 组件, 它们的水平增加比例分别是1、2、3,但容器宽度增加 60 像素时,则第一个组件宽度增加 10 像素 , 第二个组件宽度增加 20 像素,第三个组件宽度增加 30 像 素。 如 果其增 加比例为 0 , 则 表示不会增加 。 |
weighty |
设置受该对象控制的 GUI 组件占据多余空间的垂直比例 |
anchor |
设置受该对象控制的 GUI 组件在其显示区域中的定位方式:GridBagConstraints.CENTER (中间 )GridBagConstraints.NORTH (上中 ) GridBagConstraints.NORTHWEST (左上角)GridBagConstraints.NORTHEAST (右上角)GridBagConstraints.SOUTH (下中) GridBagConstraints.SOUTHEAST (右下角)GridBagConstraints.SOUTHWEST (左下角)GridBagConstraints.EAST (右中) GridBagConstraints.WEST (左中) |
GridBagLayout
使用步骤如下:
创建GridBagLaout
布局管理器对象,并给容器设置该布局管理器对象;
创建GridBagConstraints
对象,并设置该对象的控制属性:
gridx
:用于指定组件在网格中所处的横向索引;gridy
:用于执行组件在网格中所处的纵向索引;gridwidth
:用于指定组件横向跨越多少个网格;gridheight
:用于指定组件纵向跨越多少个网格;调用GridBagLayout
对象的setConstraints(Component c,GridBagConstraints gbc)
方法,把即将要添加到容器中的组件c
和GridBagConstraints对象关联起来;
把组件添加到容器中;
public class GridBagLayoutDemo {
public static void main(String[] args) {
Frame frame = new Frame("GridBagLayoutDemo");
GridBagLayout gbl = new GridBagLayout();
frame.setLayout(gbl);
GridBagConstraints gbc = new GridBagConstraints();
// 设置所有的GridBagConstraints对象的fill属性为GridBagConstraints.BOTH
// 当有空白区域时,组件自动扩大占满空白区域
gbc.fill = GridBagConstraints.BOTH;
// 设置GridBagConstraints对象的weightx设置为1,表示横向扩展比例为1
gbc.weightx = 1;
Button button1 = new Button("Button1");
Button button2 = new Button("Button2");
Button button3 = new Button("Button3");
addGBLComponent(frame,button1,gbl,gbc);
addGBLComponent(frame,button2,gbl,gbc);
addGBLComponent(frame,button3,gbl,gbc);
Button button4 = new Button("Button4");
// 把GridBagConstraints的gridwidth设置为GridBagConstraints.REMAINDER
// 则表明当前组件是横向最后一个组件
gbc.gridwidth = GridBagConstraints.REMAINDER;
addGBLComponent(frame,button4,gbl,gbc);
Button button5 = new Button("Button5");
// 由于gridwidth的值还是GridBagConstraints.REMAINDER,所以button5也会占满横向空白区域
addGBLComponent(frame,button5,gbl,gbc);
// 设置button6和button7的纵向向扩展比例为1
gbc.weighty=1;
// 把GridBagConstaints的gridheight和gridwidth设置为2,表示纵向和横向会占用两个网格
gbc.gridwidth = 2;
gbc.gridheight = 2;
Button button6 = new Button("Button6");
Button button7 = new Button("Button7");
addGBLComponent(frame,button6,gbl,gbc);
addGBLComponent(frame,button7,gbl,gbc);
// 调用pack方法,让frame的大小适应组件的大小
frame.pack();
frame.setVisible(true);
}
public static void addGBLComponent(Container container,Component component,GridBagLayout gbl,GridBagConstraints gbc) {
gbl.setConstraints(component,gbc);
container.add(component);
}
}
CardLayout 布局管理器以时间而非空间来管理它里面的组件,它将加入容器的所有组件看成一叠卡片(每个卡片其实就是一个组件),每次只有最上面的那个 Component 才可见。就好像一副扑克牌,它们叠在一起,每次只有最上面的一张扑克牌才可见。
方法名称 | 方法功能 |
---|---|
CardLayout() |
创建默认的 CardLayout 布局管理器。 |
CardLayout(int hgap,int vgap) |
通过指定卡片与容器左右边界的间距hgap 、上下边界vgap 的间距来创建 CardLayout 布局管理器. |
first(Container target) |
显示target 容器中的第一张卡片. |
last(Container target) |
显示target 容器中的最后一张卡片. |
previous(Container target) |
显示target 容器中的前一张卡片. |
next(Container target) |
显示target 容器中的后一张卡片. |
show(Container taget,String name) |
显 示 target 容器中指定名字的卡片. |
public class CardLayoutDemo {
public static void main(String[] args) {
Frame frame = new Frame("CardLayoutDemo");
// 创建一个Panel容器p1,并设置其布局管理器为CardLayout,用来存放多张卡片
Panel p1 = new Panel();
CardLayout cardLayout = new CardLayout();
p1.setLayout(cardLayout);
// 添加5张卡片
for (int i = 1; i <= 5; i++) {
String name = "Button - " + i;
p1.add(name,new Button(name));
}
// 创建一个Panel容器p2,用来存放上下翻页按钮
Panel p2 = new Panel();
// 创建按钮,并添加点击事件
ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
String command = e.getActionCommand();
switch (command){
case "上一张":
cardLayout.previous(p1);
break;
case "下一张":
cardLayout.next(p1);
break;
case "第一张":
cardLayout.first(p1);
break;
case "最后一张":
cardLayout.last(p1);
break;
case "第三张":
cardLayout.show(p1,"Button - 3");
break;
}
}
};
Button b1 = new Button("上一张");
Button b2 = new Button("下一张");
Button b3 = new Button("第一张");
Button b4 = new Button("最后一张");
Button b5 = new Button("第三张");
b1.addActionListener(actionListener);
b2.addActionListener(actionListener);
b3.addActionListener(actionListener);
b4.addActionListener(actionListener);
b5.addActionListener(actionListener);
p2.add(b1);
p2.add(b2);
p2.add(b3);
p2.add(b4);
p2.add(b5);
frame.add(p1,BorderLayout.CENTER);
frame.add(p2,BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
为了简化开发,Swing 引入了 一个新的布局管理器 : BoxLayout 。 BoxLayout 可以在垂直和水平两个方向上摆放 GUI 组件, BoxLayout 提供了如下一个简单的构造器:
方法名称 | 方法功能 |
---|---|
BoxLayout(Container target, int axis) |
指定创建基于 target 容器的 BoxLayout 布局管理器,该布局管理器里的组件按 axis 方向排列。其中 axis 有 BoxLayout.X_AXIS (横向)和 BoxLayout.Y_AXIS (纵向)两个方向。 |
public class BoxLayoutDemo {
public static void main(String[] args) {
Frame frame = new Frame("BoxLayoutDemo");
// 创建BoxLayout布局管理器,并指定容器为上面的frame对象,指定组件排列方向为横向
BoxLayout boxLayout = new BoxLayout(frame,BoxLayout.X_AXIS);
frame.setLayout(boxLayout);
frame.add(new Button("Button1"));
frame.add(new Button("Button2"));
frame.pack();
frame.setVisible(true);
}
}
在java.swing
包中,提供了一个新的容器类Box
,该容器的默认布局管理器就是BoxLayout
,大多数情况下,使用Box容器去容纳多个GUI组件,然后再把Box容器作为一个组件,添加到其他的容器中,从而形成整体窗口布局。
Box 类方法名称 |
方法功能 |
---|---|
static Box createHorizontalBox() |
创建一个水平排列组件的 Box 容器 。 |
static Box createVerticalBox() |
创建一个垂直排列组件的 Box 容器 。 |
public class BoxLayoutDemo {
public static void main(String[] args) {
//创建Frame对象
Frame frame = new Frame("BoxLayoutDemo");
//创建一个横向的Box,并添加两个按钮
Box hBox = Box.createHorizontalBox();
hBox.add(new Button("水平按钮一"));
hBox.add(new Button("水平按钮二"));
//创建一个纵向的Box,并添加两个按钮
Box vBox = Box.createVerticalBox();
vBox.add(new Button("垂直按钮一"));
vBox.add(new Button("垂直按钮二"));
//把box容器添加到frame容器中
frame.add(hBox,BorderLayout.NORTH);
frame.add(vBox);
//设置frame最佳大小并可见
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 (可在水平方向上拉伸的间距) |
public class BoxLayoutDemo {
public static void main(String[] args) {
//创建Frame对象
Frame frame = new Frame("BoxLayoutDemo");
//创建一个横向的Box,并添加两个按钮
Box hBox = Box.createHorizontalBox();
hBox.add(new Button("水平按钮一"));
hBox.add(Box.createHorizontalGlue());//两个方向都可以拉伸的间隔
hBox.add(new Button("水平按钮二"));
hBox.add(Box.createHorizontalStrut(10));//水平间隔固定,垂直间方向可以拉伸
hBox.add(new Button("水平按钮3"));
//创建一个纵向的Box,并添加两个按钮
Box vBox = Box.createVerticalBox();
vBox.add(new Button("垂直按钮一"));
vBox.add(Box.createVerticalGlue());//两个方向都可以拉伸的间隔
vBox.add(new Button("垂直按钮二"));
vBox.add(Box.createVerticalStrut(10));//垂直间隔固定,水平方向可以拉伸
vBox.add(new Button("垂直按钮三"));
//把box容器添加到frame容器中
frame.add(hBox, BorderLayout.NORTH);
frame.add(vBox);
//设置frame最佳大小并可见
frame.pack();
frame.setVisible(true);
}
}
组件名 | 功能 |
---|---|
Button |
按钮 |
Canvas |
用于绘图的画布 |
Checkbox |
复选框组件(也可当做单选框组件使用) |
CheckboxGroup |
用于将多个Checkbox 组件组合成一组, 一组 Checkbox 组件将只有一个可以被选中,即全部变成单选框组件 |
Choice |
下拉选择框 |
Frame |
窗口 , 在 GUI 程序里通过该类创建窗口 |
Label |
标签类,用于放置提示性文本 |
List |
JU表框组件,可以添加多项条目 |
Panel |
不能单独存在基本容器类,必须放到其他容器中 |
Scrollbar |
滑动条组件。如果需要用户输入位于某个范围的值 , 就可以使用滑动条组件 ,比如调 色板中设置 RGB 的三个值所用的滑动条。当创建一个滑动条时,必须指定它的方向、初始值、 滑块的大小、最小值和最大值。 |
ScrollPane |
带水平及垂直滚动条的容器组件 |
TextArea |
多行文本域 |
TextField |
单行文本框 |
public class BaseComponentDemo {
private Frame frame = new Frame("BaseComponentDemo");
private TextArea textArea = new TextArea("textArea",10,30);
private TextField textField = new TextField("textField",10);
private CheckboxGroup cbg = new CheckboxGroup();
private Checkbox boy = new Checkbox("男",cbg,true);
private Checkbox girl = new Checkbox("女",cbg,false);
private Button button = new Button("确定");
private Choice choice = new Choice();
private List list = new List(11);
private void init(){
Panel center = new Panel();
Panel bottom = new Panel();
Panel right = new Panel();
Box verticalBox = Box.createVerticalBox();
verticalBox.add(textArea);
verticalBox.add(textField);
center.add(verticalBox);
Box horizontalBox = Box.createHorizontalBox();
horizontalBox.add(boy);
horizontalBox.add(girl);
choice.add("Java");
choice.add("C++");
choice.add("Python");
horizontalBox.add(choice);
horizontalBox.add(button);
bottom.add(horizontalBox);
list.add("Windows");
list.add("Linux");
list.add("MacOS");
right.add(list);
frame.add(center,BorderLayout.CENTER);
frame.add(bottom,BorderLayout.SOUTH);
frame.add(right,BorderLayout.EAST);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new BaseComponentDemo().init();
}
}
菜单组件名称 | 功能 |
---|---|
MenuBar |
菜单条,菜单的容器 。 |
Menu |
菜单组件,菜单项的容器。它也是Menultem的子类,所以可作为菜单项使用。 |
PopupMenu |
上下文菜单组件(右键菜单组件) |
Menultem |
菜单项组件 。 |
CheckboxMenuItem |
复选框菜单项组件 |
public class MenuDemo {
private Frame frame = new Frame("MenuDemo");
private MenuBar menuBar = new MenuBar();
private TextArea textArea = new TextArea(10,30);
private void loadMenu() {
Menu fileMenu = new Menu("文件");
MenuItem openItem = new MenuItem("打开");
MenuItem saveItem = new MenuItem("保存");
fileMenu.add(openItem);
fileMenu.add(saveItem);
Menu editMenu = new Menu("编辑");
MenuItem cutItem = new MenuItem("剪切");
MenuItem copyItem = new MenuItem("复制");
MenuItem pasteItem = new MenuItem("粘贴");
editMenu.add(cutItem);
editMenu.add(copyItem);
editMenu.add(pasteItem);
Menu helpMenu = new Menu("帮助");
MenuItem aboutItem = new MenuItem("关于");
helpMenu.add(aboutItem);
editMenu.add(helpMenu);
menuBar.add(fileMenu);
menuBar.add(editMenu);
frame.setMenuBar(menuBar);
// 监听打开菜单
openItem.addActionListener(e -> {
FileDialog fd_load = new FileDialog(frame, "选择文件", FileDialog.LOAD);
fd_load.setVisible(true);
System.out.println("文件路径:" + fd_load.getDirectory() + fd_load.getFile());
});
}
private void init(){
loadMenu();
frame.add(textArea);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new MenuDemo().init();
}
}
public class PopupMenuDemo {
private Frame frame = new Frame("PopupMenuDemo");
//创建PopupMenu菜单
private PopupMenu popupMenu = new PopupMenu();
//创建菜单条
private MenuItem commentItem = new MenuItem("注释");
private MenuItem cancelItem = new MenuItem("取消注释");
private MenuItem copyItem = new MenuItem("复制");
private MenuItem pasteItem = new MenuItem("保存");
//创建一个文本域
private TextArea ta = new TextArea("Hello", 6, 40);
//创建一个Panel
private Panel panel = new Panel();
public void init(){
//把菜单项添加到PopupMenu中
popupMenu.add(commentItem);
popupMenu.add(cancelItem);
popupMenu.add(copyItem);
popupMenu.add(pasteItem);
//设置panel大小
panel.setPreferredSize(new Dimension(300,100));
//把PopupMenu添加到panel中
panel.add(popupMenu);
//为panel注册鼠标事件
panel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
// 判断当前鼠标操作是不是触发PopupMenu的操作
if (e.isPopupTrigger()){
popupMenu.show(panel,e.getX(),e.getY());
}
}
});
//把ta添加到frame中间区域中
frame.add(ta);
//把panel添加到frame底部
frame.add(panel,BorderLayout.SOUTH);
//设置frame最佳大小,并可视;
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new PopupMenuDemo().init();
}
}
Dialog
是 Window
类的子类,是一个容器类,属于特殊组件。对话框是可以独立存在的顶级窗口, 因此用法与普通窗口的用法几乎完全一样,但是使用对话框需要注意下面两点:
non-modal
)和模态(modal
)两种,当模态对话框被打开后,该模式对话框总是位于它的父窗口之上,在模态对话框被关闭之前,父窗口无法获得焦点。方法名称 | 方法功能 |
---|---|
Dialog(Frame owner, String title, boolean modal) |
创建一个对话框对象: owner :当前对话框的父窗口 ;title :当前对话框的标题;modal :当前对话框是否是模态对话框,true/false |
public class DialogDemo {
public static void main(String[] args) {
Frame frame = new Frame("DialogDemo");
Dialog d1 = new Dialog(frame,"模态对话框",true);
Dialog d2 = new Dialog(frame,"非模态对话框",false);
d1.setBounds(100,100,300,200);
d2.setBounds(100,100,300,200);
Button b1 = new Button("模态对话框");
Button b2 = new Button("非模态对话框");
b1.addActionListener(e -> {
d1.setVisible(true);
});
b2.addActionListener(e -> {
d2.setVisible(true);
});
frame.add(b1,BorderLayout.NORTH);
frame.add(b2,BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
Dialog
类还有 一个子类:FileDialog
,它代表一个文件对话框,用于打开或者保存文件,需要注意的是FileDialog
无法指定模态或者非模态,这是因为 FileDialog
依赖于运行平台的实现,如果运行平台的文件对话框是模态的,那么 FileDialog
也是模态的;否则就是非模态的 。
方法名称 | 方法功能 |
---|---|
FileDialog(Frame parent, String title, int mode) |
创建一个文件对话框。parent :指定父窗口; title :对话框标题; mode :文件对话框类型,指定为FileDialog.load 用于打开文件,指定为FileDialog.SAVE 用于保存文件 |
String getDirectory() |
获取被打开或保存文件的所在目录 |
String getFile() |
获取被打开或保存文件的文件名 |
public class FileDialogDemo {
public static void main(String[] args) {
Frame frame = new Frame("FileDialogDemo");
FileDialog fd_load = new FileDialog(frame, "选择文件", FileDialog.LOAD);
// 只能打开 jpg、png
fd_load.setFilenameFilter((dir, name) -> {
return name.endsWith(".jpg") || name.endsWith(".png");
});
FileDialog fd_save = new FileDialog(frame, "保存文件", FileDialog.SAVE);
Button b1 = new Button("选择文件");
b1.addActionListener(e -> {
fd_load.setVisible(true);
System.out.println("文件路径:" + fd_load.getDirectory() + fd_load.getFile());
});
Button b2 = new Button("保存文件");
b2.addActionListener(e -> {
fd_save.setVisible(true);
System.out.println("文件路径:" + fd_save.getDirectory() + fd_save.getFile());
});
frame.add(b1,BorderLayout.NORTH);
frame.add(b2,BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
前面介绍了如何放置各种组件,从而得到了丰富多彩的图形界面,但这些界面还不能响应用户的任何操作。比如单击前面所有窗口右上角的X
按钮,但窗口依然不会关闭。因为在 AWT 编程中 ,所有用户的操作,都必须都需要经过一套事件处理机制来完成,而 Frame 和组件本身并没有事件处理能力 。
具体的使用步骤如下:
xxxListener
接口,重写方法;addXxxListener()
方法完成注册监听public class EventDemo {
public static void main(String[] args) {
Frame frame = new Frame("EventDemo");
// 添加窗口关闭事件
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
TextField textField = new TextField(30);
Button button = new Button("Click Me");
// 添加点击事件
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
textField.setText("Button Clicked");
}
});
frame.add(textField, BorderLayout.NORTH);
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
事件监听器必须实现事件监听器接口, AWT 提供了大量的事件监听器接口用于实现不同类型的事件监听器,用于监听不同类型的事件 。 AWT 中提供了丰富的事件类,用于封装不同组件上所发生的特定操作, AWT 的事件类都是 AWTEvent
类的子类, AWTEvent
是 EventObject
的子类。
AWT把事件分为了两大类:
低级事件 | 触发时机 |
---|---|
ComponentEvent |
组件事件 , 当 组件尺寸发生变化、位置发生移动、显示/隐藏状态发生改变时触发该事件。 |
ContainerEvent |
容器事件 , 当容器里发生添加组件、删除组件时触发该事件 。 |
WindowEvent |
窗口事件, 当窗 口状态发生改变 ( 如打开、关闭、最大化、最小化)时触发该事件 。 |
FocusEvent |
焦点事件 , 当组件得到焦点或失去焦点 时触发该事件 。 |
KeyEvent |
键盘事件 , 当按键被按下、松开、单击时触发该事件。 |
MouseEvent |
鼠标事件,当进行单击、按下、松开、移动鼠标等动作 时触发该事件。 |
PaintEvent |
组件绘制事件 , 该事件是一个特殊的事件类型 , 当 GUI 组件调用 update/paint 方法来呈现自身时触发该事件,该事件并非专用于事件处理模型 。 |
高级事件 | 触发时机 |
---|---|
ActionEvent |
动作事件 ,当按钮、菜单项被单击,在 TextField 中按 Enter 键时触发 |
AjustmentEvent |
调节事件,在滑动条上移动滑块以调节数值时触发该事件。 |
ltemEvent |
选项事件,当用户选中某项, 或取消选中某项时触发该事件 。 |
TextEvent |
文本事件, 当文本框、文本域里的文本发生改变时触发该事件。 |
不同的事件需要使用不同的监听器监听,不同的监听器需要实现不同的监听器接口, 当指定事件发生后 , 事件监听器就会调用所包含的事件处理器(实例方法)来处理事件 。
事件类别 | 描述信息 | 监听器接口名 |
---|---|---|
ActionEvent |
激活组件 | ActionListener |
ItemEvent |
选择了某些项目 | ItemListener |
MouseEvent |
鼠标移动 | MouseMotionListener |
MouseEvent |
鼠标点击等 | MouseListener |
KeyEvent |
键盘输入 | KeyListener |
FocusEvent |
组件收到或失去焦点 | FocusListener |
AdjustmentEvent |
移动了滚动条等组件 | AdjustmentListener |
ComponentEvent |
对象移动缩放显示隐藏等 | ComponentListener |
WindowEvent |
窗口收到窗口级事件 | WindowListener |
ContainerEvent |
容器中增加删除了组件 | ContainerListener |
TextEvent |
文本字段或文本区发生改变 | TextListener |