目录
GUI编程AWT
简介:
AWT“抽象窗口工具集”
AWT的继承体系
布局管理
AWT中常用组件
基本组件
对话框Dialog
GUI事件处理机制
GUI中常见事件和事件监听器
事件监听
单击事件
画笔
Graphics类的使用(画图)
鼠标事件(模拟画图工具)
窗口监听
键盘监听
菜单组件
GUI编程AWT
简介:
AWT“抽象窗口工具集”
AWT“抽象窗口工具集”
AWT是窗口架构,它从不同平台的窗口系统中抽取共同组件,当程序运行时,将这些组件的创建和动作委托给程序所在的运行平台。
简而言之,当使用AWT编写图形界面应用的时候,程序仅指定了界面组件的位置和行为,并未提供真正的表现,JVM调用操作系统本地的图形化界面来创建和平台一致的对等体。
AWT的继承体系
所有和 AWT 编程相关的类都放在 java.awt 包以及它的子包中, AWT 编程中有两个基类 :Component和 MenuComponent。
- Component:代表一个能以图形化方式显示出来,并可与用户交互的对象,例如 Button 代表一个按钮,TextField 代表 一个文本框等;
- MenuComponent:则代表图形界面的菜单组件,包括 MenuBar (菜单条)、 Menultem (菜单项)等子类。
其中 Container 是一种特殊的 Component,它代表一种容器,可以盛装普通的 Component。
AWT中还有一个非常重要的接口叫LayoutManager ,如果一个容器中有多个组件,那么容器就需要使用LayoutManager来管理这些组件的布局方式。
Frame
package 数字图像化处理AWT;
import java.awt.*;
public class Text01 {
public static void main(String[] args) {
Frame fs=new Frame("海绵hong");
fs.setVisible(true);//设置可见性
fs.setSize(500,500);//设置窗口大小
fs.setBackground(new Color(1,1,1));//背景颜色
fs.setLocation(300,300);//弹出的初始位置
fs.pack();//最合适的fs大小
fs.setResizable(false);//大小固定(默认为true可以变化)
}
}
package 数字图像化处理AWT;
import java.awt.*;
//使用封装进行多个窗口的创建
public class Text02 {
public static void main(String[] args) {
Myfr my1=new Myfr(1000,1000,2000,2000,Color.red);
Myfr my2=new Myfr(3000,1000,2000,2000,Color.yellow);
Myfr my3=new Myfr(100,300,200,200,Color.black);
Myfr my4=new Myfr(300,300,200,200,Color.pink);
System.out.println(my3.id);
}
}
class Myfr extends Frame{
static int id=0;
public Myfr(int x,int y,int h,int w,Color color){
super("myfr"+(++id));
setBackground(color);
setBounds(x,y,h,w);
setVisible(true);
}
面板Panel(内嵌与Frame)
package 数字图像化处理AWT;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Text03{
public static void main(String[] args) {
//1.创建Frame容器对象
Frame frame = new Frame("这里在测试Panel");
//2.创建Panel容器对象
Panel panel = new Panel();
//4.把Panel添加到Frame中
frame.add(panel);
//5.设置Frame的位置和大小
frame.setBounds(30,30,500,300);
//6.设置Frame可见
frame.setVisible(true);
//监听事件,监听窗口关闭事件
//适配器模式:
frame.addWindowListener(new WindowAdapter() {
//窗口点击关闭时需要做的事情
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}}
布局管理
之前,我们介绍了Component中有一个方法 setBounds() 可以设置当前容器的位置和大小,但是我们需要明确一件事,如果我们手动的为组件设置位置和大小的话,就会造成程序的不通用性,例如:
Label label = new Label("你好,世界");
创建了一个lable组件,很多情况下,我们需要让lable组件的宽高和“你好,世界”这个字符串自身的宽高一致,这种大小称为最佳大小。由于操作系统存在差异,例如在windows上,我们要达到这样的效果,需要把该Lable组件的宽和高分别设置为100px,20px,但是在Linux操作系统上,可能需要把Lable组件的宽和高分别设置为120px,24px,才能达到同样的效果。
如果要让我们的程序在不同的操作系统下,都有相同的使用体验,那么手动设置组件的位置和大小,无疑是一种灾难,因为有太多的组件,需要分别设置不同操作系统下的大小和位置。为了解决这个问题,Java提供了LayoutManager布局管理器,可以根据运行平台来自动调整组件大小,程序员不用再手动设置组件的大小和位置了,只需要为容器选择合适的布局管理器即可。
1.流式布局(FlowLayout)
在 FlowLayout 布局管理器 中,组件像水流一样向某方向流动 (排列) ,遇到障碍(边界)就折回,重头开始排列 。在默认情况下, FlowLayout 布局管理器从左向右排列所有组件,遇到边界就会折回下一行重新开始。
| 构造方法 | 方法功能 |
|---|---|
| FlowLayout() | 使用默认 的对齐方式及默认的垂直间距、水平间距创建 FlowLayout 布局管理器。 |
| FlowLayout(int align) | 使用指定的对齐方式及默认的垂直间距、水平间距创建 FlowLayout 布局管理器。 |
| FlowLayout(int align,int hgap,int vgap) | 使用指定的对齐方式及指定的垂直问距、水平间距创建FlowLayout 布局管理器。 |
FlowLayout 中组件的排列方向(从左向右、从右向左、从中间向两边等) , 该参数应该使用FlowLayout类的静态常量 : FlowLayout. LEFT 、 FlowLayout. CENTER 、 FlowLayout. RIGHT ,默认是左对齐。
FlowLayout 中组件中间距通过整数设置,单位是像素,默认是5个像素。
package 数字图像化处理AWT;
import java.awt.*;
public class Text04{
public static void main(String[] args) {
//1.创建Frame对象,并且标题设置为计算器
Frame frame = new Frame("计算器");
//2.创建一个Panel对象,并且往Panel中放置一个TextField组件
Panel p1 = new Panel();
p1.add(new TextField(30));
//3.把上述的Panel放入到Frame的北侧区域
frame.add(p1,BorderLayout.NORTH);
//4.创建一个Panel对象,并且设置其布局管理器为GridLayout
Panel p2 = new Panel();
p2.setLayout(new GridLayout(3,5,4,4));
//5.往上述Panel中,放置15个按钮,内容依次是:0,1,2,3,4,5,6,7,8,9,+,-,*,/,.
for (int i = 0; i < 10; 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("."));
//6.把上述Panel添加到Frame的中间区域中国
frame.add(p2);
//7.设置Frame为最佳大小
frame.pack();
//8.设置Frame可见
frame.setVisible(true);
}
}
2.东西南北中(BorderLayout)
BorderLayout 将容器分为 EAST 、 SOUTH 、 WEST 、 NORTH 、 CENTER五个区域,普通组件可以被放置在这 5 个区域的任意一个中 。 BorderLayout布局 管理器的布局示意图如图所示 。
当改变使用 BorderLayout 的容器大小时, NORTH 、 SOUTH 和 CENTER区域水平调整,而 EAST 、 WEST 和 CENTER 区域垂直调整。使用BorderLayout 有如下两个注意点:
-
当向使用 BorderLayout 布局管理器的容器中添加组件时 , 需要指定要添加到哪个区域中 。 如果没有指定添加到哪个区域中,则默认添加到中间区域中;
-
如果向同一个区域中添加多个组件时 , 后放入的组件会覆盖先放入的组件;
| 构造方法 | 方法功能 |
|---|---|
| BorderLayout() | 使用默认的水平间距、垂直 间距创建 BorderLayout 布局管理器 。 |
| BorderLayout(int hgap,int vgap): | 使用指定的水平间距、垂直间距创建 BorderLayout 布局管理器。 |
代码演示1:
package 数字图像化处理AWT;
import java.awt.*;
public class Text05 {
public static void main(String[] args) {
//1.创建Frame对象
Frame frame = new Frame("这里测试BorderLayout");
//2.指定Frame对象的布局管理器为BorderLayout
frame.setLayout(new BorderLayout(300,50));
//3.往Frame指定东南西北中各添加一个按钮组件
frame.add(new Button("east"), BorderLayout.EAST);
frame.add(new Button("west"), BorderLayout.WEST);
frame.add(new Button("south"), BorderLayout.SOUTH);
frame.add(new Button("north"), BorderLayout.NORTH);
frame.add(new Button("center"), BorderLayout.CENTER);
//4.设置Frame为最佳大小
frame.pack();
//5.设置Frame可见
frame.setVisible(true);
}
}
表格布局(GridLayout)
GridLayout 布局管理器将容器分割成纵横线分隔的网格 , 每个网格所占的区域大小相同。当向使用 GridLayout 布局管理器的容器中添加组件时, 默认从左向右、 从上向下依次添加到每个网格中 。 与 FlowLayout不同的是,放置在 GridLayout 布局管理器中的各组件的大小由组件所处的区域决定(每 个组件将自动占满整个区域) 。
| 构造方法 | 方法功能 |
|---|---|
| GridLayout(int rows,in t cols) | 采用指定的行数、列数,以及默认的横向间距、纵向间距将容器 分割成多个网格 |
| GridLayout(int rows,int cols,int hgap,int vgap) | 采用指定 的行数、列 数 ,以及指定的横向间距 、 纵向间距将容器分割成多个网格。 |
案例:
使用Frame+Panel,配合FlowLayout和GridLayout完成一个计算器效果。
代码:
package 数字图像化处理AWT;
import java.awt.*;
public class Text06{
public static void main(String[] args) {
//1.创建Frame对象,并且标题设置为计算器
Frame frame = new Frame("计算器");
//2.创建一个Panel对象,并且往Panel中放置一个TextField组件
Panel p1 = new Panel();
p1.add(new TextField(30));
//3.把上述的Panel放入到Frame的北侧区域
frame.add(p1,BorderLayout.NORTH);
//4.创建一个Panel对象,并且设置其布局管理器为GridLayout
Panel p2 = new Panel();
p2.setLayout(new GridLayout(3,5,4,4));
//5.往上述Panel中,放置15个按钮,内容依次是:0,1,2,3,4,5,6,7,8,9,+,-,*,/,.
for (int i = 0; i < 10; 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("."));
//6.把上述Panel添加到Frame的中间区域中国
frame.add(p2);
//7.设置Frame为最佳大小
frame.pack();
//8.设置Frame可见
frame.setVisible(true);
}
}
重叠卡牌 (CardLayout)
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 taget,String name) | 显 示 target 容器中指定名字的卡片. |
案例:
使用Frame和Panel以及CardLayout完成下图中的效果,点击底部的按钮,切换卡片
演示代码:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class CardLayoutDemo {
public static void main(String[] args) {
//1.创建Frame对象
Frame frame = new Frame("这里测试CardLayout");
//2.创建一个String数组,存储不同卡片的名字
String[] names = {"第一张","第二张","第三张","第四张","第五张"};
//3.创建一个Panel容器p1,并设置其布局管理器为CardLayout,用来存放多张卡片
CardLayout cardLayout = new CardLayout();
Panel p1 = new Panel();
p1.setLayout(cardLayout);
//4.往p1中存储5个Button按钮,名字从String数组中取
for (int i = 0; i < 5; i++) {
p1.add(names[i],new Button(names[i]));
}
//5.创建一个Panel容器p2,用来存储5个按钮,完成卡片的切换
Panel p2 = new Panel();
//6.创建5个按钮,并给按钮设置监听器
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(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,"第三张");
break;
}
}
};
Button b1 = new Button("上一张");
Button b2 = new Button("下一张");
Button b3 = new Button("第一张");
Button b4 = new Button("最后一张");
Button b5 = new Button("第三张");
b1.addActionListener(listener);
b2.addActionListener(listener);
b3.addActionListener(listener);
b4.addActionListener(listener);
b5.addActionListener(listener);
//7.把5个按钮添加到p2中
p2.add(b1);
p2.add(b2);
p2.add(b3);
p2.add(b4);
p2.add(b5);
//8.把p1添加到frame的中间区域
frame.add(p1);
//9.把p2添加到frame的底部区域
frame.add(p2,BorderLayout.SOUTH);
//10设置frame最佳大小并可见
frame.pack();
frame.setVisible(true);
}
}
垂直水平布局器( 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:
import javax.swing.*;
import java.awt.*;
public class BoxLayoutDemo1 {
public static void main(String[] args) {
//1.创建Frame对象
Frame frame = new Frame("这里测试BoxLayout");
//2.创建BoxLayout布局管理器,并指定容器为上面的frame对象,指定组件排列方向为纵向
BoxLayout boxLayout = new BoxLayout(frame, BoxLayout.Y_AXIS);
frame.setLayout(boxLayout);
//3.往frame对象中添加两个按钮
frame.add(new Button("按钮1"));
frame.add(new Button("按钮2"));
//4.设置frame最佳大小,并可见
frame.pack();
frame.setVisible(true);
}
}
在java.swing包中,提供了一个新的容器Box,该容器的默认布局管理器就是BoxLayout,大多数情况下,使用Box容器去容纳多个GUI组件,然后再把Box容器作为一个组件,添加到其他的容器中,从而形成整体窗口布局。
| 方法名称 | 方法功能 |
|---|---|
| static Box createHorizontalBox() | 创建一个水平排列组件的 Box 容器 。 |
| static Box createVerticalBox() | 创建一个垂直排列组件的 Box 容器 。 |
案例2:
使用Frame和Box,完成下图效果:
演示代码2:
import javax.swing.*;
import java.awt.*;
public class BoxLayoutDemo2 {
public static void main(String[] args) {
//1.创建Frame对象
Frame frame = new Frame("这里测试BoxLayout");
//2.创建一个横向的Box,并添加两个按钮
Box hBox = Box.createHorizontalBox();
hBox.add(new Button("水平按钮一"));
hBox.add(new Button("水平按钮二"));
//3.创建一个纵向的Box,并添加两个按钮
Box vBox = Box.createVerticalBox();
vBox.add(new Button("垂直按钮一"));
vBox.add(new Button("垂直按钮二"));
//4.把box容器添加到frame容器中
frame.add(hBox,BorderLayout.NORTH);
frame.add(vBox);
//5.设置frame最佳大小并可见
frame.pack();
frame.setVisible(true);
}
}
通过之前的两个BoxLayout演示,我们会发现,被它管理的容器中的组件之间是没有间隔的,不是特别的美观,但之前学习的几种布局,组件之间都会有一些间距,那使用BoxLayout如何给组件设置间距呢?
其实很简单,我们只需要在原有的组件需要间隔的地方,添加间隔即可,而每个间隔可以是一个组件,只不过该组件没有内容,仅仅起到一种分隔的作用。
Box类中,提供了5个方便的静态方法来生成这些间隔组件:
| 方法名称 | 方法功能 |
|---|---|
| static Component createHorizontalGlue() | 创建一条水平 Glue (可在两个方向上同时拉伸的间距) |
| static Component createVerticalGlue() | 创建一条垂直 Glue (可在两个方向上同时拉伸的间距) |
| static Component createHorizontalStrut(int width) | 创建一条指定宽度(宽度固定了,不能拉伸)的水平Strut (可在垂直方向上拉伸的间距) |
| static Component createVerticalStrut(int height) | 创建一条指定高度(高度固定了,不能拉伸)的垂直Strut (可在水平方向上拉伸的间距) |
案例3:
使用Frame和Box,完成下图效果:
演示代码3:
import javax.swing.*;
import java.awt.*;
public class BoxLayoutDemo3 {
public static void main(String[] args) {
//1.创建Frame对象
Frame frame = new Frame("这里测试BoxLayout");
//2.创建一个横向的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"));
//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("垂直按钮三"));
//4.把box容器添加到frame容器中
frame.add(hBox, BorderLayout.NORTH);
frame.add(vBox);
//5.设置frame最佳大小并可见
frame.pack();
frame.setVisible(true);
}
}
AWT中常用组件
基本组件
| 组件名 | 功能 |
|---|---|
| Button | Button |
| Canvas | 用于绘图的画布 |
| Checkbox | 复选框组件(也可当做单选框组件使用) |
| CheckboxGroup | 用于将多个Checkbox 组件组合成一组, 一组 Checkbox 组件将只有一个可以 被选中 , 即全部变成单选框组件 |
| Choice | 下拉选择框 |
| Frame | 窗口 , 在 GUI 程序里通过该类创建窗口 |
| Label | 标签类,用于放置提示性文本 |
| List | JU表框组件,可以添加多项条目 |
| Panel | 不能单独存在基本容器类,必须放到其他容器中 |
| Scrollbar | 滑动条组件。如果需要用户输入位于某个范围的值 , 就可以使用滑动条组件 ,比如调 色板中设置 RGB 的三个值所用的滑动条。当创建一个滑动条时,必须指定它的方向、初始值、 滑块的大小、最小值和最大值。 |
| ScrollPane | 带水平及垂直滚动条的容器组件 |
| TextArea | 多行文本域 |
| TextField | 单行文本框 |
这些 AWT 组件的用法比较简单,可以查阅 API 文档来获取它们各自的构方法、成员方法等详细信息。
案例:
实现下图效果:
演示代码:
import javax.swing.*;
import java.awt.*;
public class BasicComponentDemo {
Frame frame = new Frame("这里测试基本组件");
//定义一个按钮
Button ok = new Button("确认");
//定义一个复选框组
CheckboxGroup cbg = new CheckboxGroup();
//定义一个单选框,初始处于被选中状态,并添加到cbg组中
Checkbox male = new Checkbox("男", cbg, true);
//定义一个单选框,初始处于未被选中状态,并添加到cbg组中
Checkbox female = new Checkbox("女", cbg, false);
//定义一个复选框,初始处于未被选中状态
Checkbox married = new Checkbox("是否已婚?", false);
//定义一个下拉选择框
Choice colorChooser = new Choice();
//定义一个列表选择框
List colorList = new List(6, true);
//定义一个5行,20列的多行文本域
TextArea ta = new TextArea(5, 20);
//定义一个50列的单行文本域
TextField tf = new TextField(50);
public void init() {
//往下拉选择框中添加内容
colorChooser.add("红色");
colorChooser.add("绿色");
colorChooser.add("蓝色");
//往列表选择框中添加内容
colorList.add("红色");
colorList.add("绿色");
colorList.add("蓝色");
//创建一个装载按钮和文本框的Panel容器
Panel bottom = new Panel();
bottom.add(tf);
bottom.add(ok);
//把bottom添加到Frame的底部
frame.add(bottom,BorderLayout.SOUTH);
//创建一个Panel容器,装载下拉选择框,单选框和复选框
Panel checkPanel = new Panel();
checkPanel.add(colorChooser);
checkPanel.add(male);
checkPanel.add(female);
checkPanel.add(married);
//创建一个垂直排列的Box容器,装载 多行文本域和checkPanel
Box topLeft = Box.createVerticalBox();
topLeft.add(ta);
topLeft.add(checkPanel);
//创建一个水平排列的Box容器,装载topLeft和列表选择框
Box top = Box.createHorizontalBox();
top.add(topLeft);
top.add(colorList);
//将top添加到frame的中间区域
frame.add(top);
//设置frame最佳大小并可见
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new BasicComponentDemo().init();
}
}
对话框Dialog
Dialog
Dialog 是 Window 类的子类,是 一个容器类,属于特殊组件 。 对话框是可以独立存在的顶级窗口, 因此用法与普通窗口的用法几乎完全一样,但是使用对话框需要注意下面两点:
-
对话框通常依赖于其他窗口,就是通常需要有一个父窗口;
-
对话框有非模式(non-modal)和模式(modal)两种,当某个模式对话框被打开后,该模式对话框总是位于它的父窗口之上,在模式对话框被关闭之前,父窗口无法获得焦点。
| 方法名称 | 方法功能 |
|---|---|
| Dialog(Frame owner, String title, boolean modal) | 创建一个对话框对象: owner:当前对话框的父窗口 title:当前对话框的标题 modal:当前对话框是否是模式对话框,true/false |
案例1:
通过Frame、Button、Dialog实现下图效果:
演示代码1:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class DialogDemo1 {
public static void main(String[] args) {
Frame frame = new Frame("这里测试Dialog");
Dialog d1 = new Dialog(frame, "模式对话框", true);
Dialog d2 = new Dialog(frame, "非模式对话框", false);
Button b1 = new Button("打开模式对话框");
Button b2 = new Button("打开非模式对话框");
//设置对话框的大小和位置
d1.setBounds(20,30,300,400);
d2.setBounds(20,30,300,400);
//给b1和b2绑定监听事件
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);
}
});
//把按钮添加到frame中
frame.add(b1);
frame.add(b2,BorderLayout.SOUTH);
//设置frame最佳大小并可见
frame.pack();
frame.setVisible(true);
}
}
在Dialog对话框中,可以根据需求,自定义内容
案例:
点击按钮,弹出一个模式对话框,其内容如下:
演示代码:
public class DialogDemo2 {
public static void main(String[] args) {
Frame frame = new Frame("这里测试Dialog");
Dialog d1 = new Dialog(frame, "模式对话框", true);
//往对话框中添加内容
Box vBox = Box.createVerticalBox();
vBox.add(new TextField(15));
vBox.add(new JButton("确认"));
d1.add(vBox);
Button b1 = new Button("打开模式对话框");
//设置对话框的大小和位置
d1.setBounds(20,30,200,100);
//给b1绑定监听事件
b1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
d1.setVisible(true);
}
});
//把按钮添加到frame中
frame.add(b1);
//设置frame最佳大小并可见
frame.pack();
frame.setVisible(true);
}
}
FileDialog
Dialog 类还有 一个子类 : FileDialog ,它代表一个文件对话框,用于打开或者保存 文件,需要注意的是FileDialog无法指定模态或者非模态,这是因为 FileDialog 依赖于运行平台的实现,如果运行平台的文件对话框是模态的,那么 FileDialog 也是模态的;否则就是非模态的 。
| 方法名称 | 方法功能 |
|---|---|
| FileDialog(Frame parent, String title, int mode) | 创建一个文件对话框: parent:指定父窗口 title:对话框标题 mode:文件对话框类型,如果指定为FileDialog.load,用于打开文件,如果指定为FileDialog.SAVE,用于保存文件 |
| String getDirectory() | 获取被打开或保存文件的绝对路径 |
| String getFile() | 获取被打开或保存文件的文件名 |
案例2:
使用 Frame、Button和FileDialog完成下图效果:
演示代码2:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class FileDialogTest {
public static void main(String[] args) {
Frame frame = new Frame("这里测试FileDialog");
FileDialog d1 = new FileDialog(frame, "选择需要加载的文件", FileDialog.LOAD);
FileDialog d2 = new FileDialog(frame, "选择需要保存的文件", FileDialog.SAVE);
Button b1 = new Button("打开文件");
Button b2 = new Button("保存文件");
//给按钮添加事件
b1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
d1.setVisible(true);
//打印用户选择的文件路径和名称
System.out.println("用户选择的文件路径:"+d1.getDirectory());
System.out.println("用户选择的文件名称:"+d1.getFile());
}
});
System.out.println("-------------------------------");
b2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
d2.setVisible(true);
//打印用户选择的文件路径和名称
System.out.println("用户选择的文件路径:"+d2.getDirectory());
System.out.println("用户选择的文件名称:"+d2.getFile());
}
});
//添加按钮到frame中
frame.add(b1);
frame.add(b2,BorderLayout.SOUTH);
//设置frame最佳大小并可见
frame.pack();
frame.setVisible(true);
}
}
GUI事件处理机制
定义:
当在某个组件上发生某些操作的时候,会自动的触发一段代码的执行。
在GUI事件处理机制中涉及到4个重要的概念需要理解:
事件源(Event Source):操作发生的场所,通常指某个组件,例如按钮、窗口等; 事件(Event):在事件源上发生的操作可以叫做事件,GUI会把事件都封装到一个Event对象中,如果需要知道该事件的详细信息,就可以通过Event对象来获取。 事件监听器(Event Listener):当在某个事件源上发生了某个事件,事件监听器就可以对这个事件进行处理。
注册监听:把某个事件监听器(A)通过某个事件(B)绑定到某个事件源(C)上,当在事件源C上发生了事件B之后,那么事件监听器A的代码就会自动执行。
使用步骤:
1.创建事件源组件对象;
2.自定义类,实现XxxListener接口,重写方法;
3.创建事件监听器对象(自定义类对象)
4.调用事件源组件对象的addXxxListener方法完成注册监听
案例:
完成下图效果,点击确定按钮,在单行文本域内显示 hello world:
演示代码:
public class EventDemo1 {
Frame frame = new Frame("这里测试事件处理");
//事件源
Button button = new Button("确定");
TextField tf = new TextField(30);
public void init(){
//注册监听
button.addActionListener(new MyActionListener());
//添加组件到frame中
frame.add(tf);
frame.add(button,BorderLayout.SOUTH);
//设置frame最佳大小并可见
frame.pack();
frame.setVisible(true);
}
//自定义事件监听器类
private class MyActionListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("用户点击了确定按钮");
tf.setText("hello world");
}
}
public static void main(String[] args) {
new EventDemo1().init();
}
}
GUI中常见事件和事件监听器
事件监听器必须实现事件监听器接口, AWT 提供了大量的事件监听器接口用于实现不同类型的事件监听器,用于监听不同类型的事件 。 AWT 中提供了丰富的事件类,用于封装不同组件上所发生的特定操作, AWT 的事件类都是 AWTEvent 类的子类 , AWTEvent是 EventObject 的子类。
事件
AWT把事件分为了两大类:
1.低级事件:这类事件是基于某个特定动作的事件。比如进入、点击、拖放等动作的鼠标事件,再比如得到焦点和失去焦点等焦点事件。
| 事件 | 触发时机 |
|---|---|
| ComponentEvent | 组件事件 , 当 组件尺寸发生变化、位置发生移动、显示/隐藏状态发生改变时触发该事件。 |
| ContainerEvent | 容器事件 , 当容器里发生添加组件、删除组件时触发该事件 。 |
| WindowEvent | 窗口事件, 当窗 口状态发生改变 ( 如打开、关闭、最大化、最 小化)时触发该事件 。 |
| FocusEvent | 焦点事件 , 当组件得到焦点或失去焦点 时触发该事件 。 |
| KeyEvent | 键盘事件 , 当按键被按下、松开、单击时触发该事件。 |
| MouseEvent | 鼠标事件,当进行单击、按下、松开、移动鼠标等动作 时触发该事件。 |
| PaintEvent | 组件绘制事件 , 该事件是一个特殊的事件类型 , 当 GUI 组件调 用 update/paint 方法 来呈现自身时触发该事件,该事件并非专用于事件处理模型 。 |
2.高级事件:这类事件并不会基于某个特定动作,而是根据功能含义定义的事件。
| 事件 | 触发时机 |
|---|---|
| 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 |
案例
案例一:
通过ContainerListener监听Frame容器添加组件;
通过TextListener监听TextFiled内容变化;
通过ItemListener监听Choice条目选中状态变化;
演示代码一:
import java.awt.*;
import java.awt.event.ContainerAdapter;
import java.awt.event.ContainerEvent;
import java.awt.event.TextEvent;
import java.awt.event.TextListener;
public class ListenerDemo1 {
public static void main(String[] args) {
Frame frame = new Frame("这里测试监听器");
//创建一个单行文本域
TextField tf = new TextField(30);
//给文本域添加TextListener,监听内容的变化
tf.addTextListener(new TextListener() {
@Override
public void textValueChanged(TextEvent e) {
System.out.println("当前内容:"+tf.getText());;
}
});
//给frame注册ContainerListener监听器,监听容器中组件的添加
frame.addContainerListener(new ContainerAdapter() {
@Override
public void componentAdded(ContainerEvent e) {
Component child = e.getChild();
System.out.println("容器中添加了新组件:"+child);
}
});
//添加tf到frame
frame.add(tf);
//设置frame最佳大小并可见
frame.pack();
frame.setVisible(true);
}
}
单击事件
案例2:
鼠标点击事件和关闭窗口
演示代码2:
package 数字图像化处理AWT;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Text09 {
public static void main(String[] args) {
Frame fs=new Frame();
Button bs=new Button("handsome boy");
//因为,addActionListener()需要一个ActActionListener,所以我们要构造一个ActionListener
Myaction myaction = new Myaction();
bs.addActionListener(myaction);//设置鼠标点击事件
fs.add(bs,BorderLayout.CENTER);
fs.pack();
Myexit(fs);
fs.setVisible(true);
}
private static void Myexit(Frame fs) {
fs.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
class Myaction implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("海绵hong贼帅");
}
}
演示代码2:计算器雏形
package 数字图像化处理AWT;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Text12 {
public static void main(String[] args) {
Frame fs = new Frame();
new MyFrame1();
}
}
class MyFrame1 extends Frame {
public MyFrame1() {
TextField tf = new TextField();
add(tf);
Mya ma = new Mya();
tf.addActionListener(ma);
pack();
setVisible(true);
tf.setEchoChar('*');//设置替换字符
}
class Mya implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
TextField fe=(TextField) e.getSource();//获得一些资源,返回一个对象
System.out.println(fe.getText());
fe.setText(" ");//输出完之后为空
}
}
}
面向对象实现简易计算器(组合)
package 数字图像化处理AWT;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Text11 {
public static void main(String[] args) {
new Calculator();
Frame fs = new Frame();
}
}
class Calculator extends Frame {
TextField num1,num2,num3;
public Calculator() {
num1 = new TextField();
num2 = new TextField();
num3 = new TextField();
Button b1 = new Button("=");
b1.addActionListener(new jian(this));
Label label = new Label("+");
setLayout(new FlowLayout());
add(num1);
add(label);
add(num2);
add(b1);
add(num3);
pack();
setVisible(true);
}
}
//监听器类
class jian implements ActionListener {
//在一个类里面组合另外一个类
Calculator calcu = null;
public jian(Calculator calcu) {
this.calcu = calcu;
}
@Override
public void actionPerformed(ActionEvent e) {
int n1=Integer.parseInt( calcu.num1.getText());
int n2=Integer.parseInt( calcu.num2.getText());
calcu.num3.setText("" + (n1+n2));
calcu.num1.setText("");
calcu.num2.setText("");
}
}
通过内部类的简化
package 数字图像化处理AWT;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Text11 {
public static void main(String[] args) {
new Calculator();
Frame fs = new Frame();
}
}
class Calculator extends Frame {
TextField num1,num2,num3;
public Calculator() {
num1 = new TextField();
num2 = new TextField();
num3 = new TextField();
Button b1 = new Button("=");
b1.addActionListener(new jian());
Label label = new Label("+");
setLayout(new FlowLayout());
add(num1);
add(label);
add(num2);
add(b1);
add(num3);
pack();
setVisible(true);
}
private class jian implements ActionListener {
public jian() {
}
@Override
public void actionPerformed(ActionEvent e) {
int n1=Integer.parseInt( num1.getText());
int n2=Integer.parseInt( num2.getText());
num3.setText("" + (n1+n2));
num1.setText("");
num2.setText("");
}
}
}
//监听器类
画笔
package 数字图像化处理AWT;
import java.awt.*;
public class Text13 {
public static void main(String[] args) {
new Mycs().loadFrame();
}
}
class Mycs extends Frame{
public void loadFrame(){
setBounds(300,300,500,500);
setVisible(true);
}
@Override
public void paint(Graphics g) {
g.setColor(Color.blue);
g.fillOval(100,100,25,25);
g.setColor(Color.cyan);
g.fillRect(200,200,100,100);
}
}
使用完画笔之后要将画笔还原回原来的颜色,---黑色
同时后期我们会学习一个函数会在过程中按照时间变换图像,这样就可以实现简单的动画
Graphics类的使用(画图)
实际生活中如果需要画图,首先我们得准备一张纸,然后在拿一支画笔,配和一些颜色,就可以在纸上画出来各种各样的图形,例如圆圈、矩形等等。
程序中绘图也一样,也需要画布,画笔,颜料等等。AWT中提供了Canvas类充当画布,提供了Graphics类来充当画笔,通过调用Graphics对象的setColor()方法可以给画笔设置颜色。
画图的步骤:
1.自定义类,继承Canvas类,重写paint(Graphics g)方法完成画图;
2.在paint方法内部,真正开始画图之前调用Graphics对象的setColor()、setFont()等方法设置画笔的颜色、字体等属性;
3.调用Graphics画笔的drawXxx()方法开始画图。
其实画图的核心就在于使用Graphics画笔在Canvas画布上画出什么颜色、什么样式的图形,所以核心在画笔上,下表中列出了Graphics类中常用的一些方法:
| 方法名称 | 方法功能 |
|---|---|
| setColor(Color c) | 设置颜色 |
| setFont(Font font) | 设置字体 |
| drawLine() | 绘制直线 |
| drawRect() | 绘制矩形 |
| drawRoundRect() | 绘制圆角矩形 |
| drawOval() | 绘制椭圆形 |
| drawPolygon() | 绘制多边形 |
| drawArc() | 绘制圆弧 |
| drawPolyline() | 绘制折线 |
| fillRect() | 填充矩形区域 |
| fillRoundRect() | 填充圆角矩形区域 |
| fillOval() | 填充椭圆区域 |
| fillPolygon() | 填充多边形区域 |
| fillArc() | 填充圆弧对应的扇形区域 |
| drawImage() | 绘制位图 |
鼠标事件(模拟画图工具)
package 数字图像化处理AWT;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Iterator;
public class Test14 {
public static void main(String[] args) {
new MyFrame("画图");
}
}
class MyFrame extends Frame {
//画画需要画笔,需要监听鼠标当前的位置,需要集合来存储这个点
ArrayList points;
public MyFrame(String s) {
super(s);
points = new ArrayList<>();
setBounds(100, 100, 600, 600);
setVisible(true);
this.addMouseListener(new Myjian());
}
@Override
public void paint(Graphics g) {
Iterator it = points.iterator();
while (it.hasNext()) {
Point point = (Point) it.next();
g.setColor(Color.blue);
g.fillOval(point.x, point.y, 10, 10);
}
}
private void addPoint(Point point) {
points.add(point);
}
public class Myjian extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
//当我们点击的时候,就会在界面出现一个点
//这个点就是鼠标的点
MyFrame fs = (MyFrame) e.getSource();//返回当前对象
fs.addPoint(new Point(e.getX(),e.getY()));
fs.repaint();//刷新
}
}
}
画图概念理解图:
窗口监听
给Frame设置WindowListner,监听用户点击 X 的动作,如果用户点击X,则关闭当前窗口
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class ListenerDemo2 {
public static void main(String[] args) {
Frame frame = new Frame("这里测试WindowListener");
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.setBounds(200,200,500,300);
frame.setVisible(true);
}
}
键盘监听
package 数字图像化处理AWT;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.security.KeyPair;
public class Text14 {
public static void main(String[] args) {
new Mykey();
}
}
class Mykey extends Frame {
public Mykey(){
setBounds(100,100,500,500);
setVisible(true);
this.addKeyListener(new KeyAdapter() {
//键盘按下
@Override
public void keyPressed(KeyEvent e) {
//获取当前键盘的码
int keycode=e.getKeyCode();
if (keycode==KeyEvent.VK_UP)
System.out.println("你点击了向上键");
}
//按下那个键进行某个操作
});
}
}
菜单组件
前面讲解了如果构建GUI界面,其实就是把一些GUI的组件,按照一定的布局放入到容器中展示就可以了。在实际开发中,除了主界面,还有一类比较重要的内容就是菜单相关组件,可以通过菜单相关组件很方便的使用特定的功能,在AWT中,菜单相关组件的使用和之前学习的组件是一模一样的,只需要把菜单条、菜单、菜单项组合到一起,按照一定的布局,放入到容器中即可。
下表中给出常见的菜单相关组件:
| 菜单组件名称 | 功能 |
|---|---|
| MenuBar | 菜单条 , 菜单的容器 。 |
| Menu | 菜单组件 , 菜单项的容器 。 它也是Menultem的子类 ,所以可作为菜单项使用 |
| PopupMenu | 上下文菜单组件(右键菜单组件) |
| Menultem | 菜单项组件 。 |
| CheckboxMenuItem | 复选框菜单项组件 |
下图是常见菜单相关组件集成体系图:
菜单相关组件使用:
1.准备菜单项组件,这些组件可以是MenuItem及其子类对象
2.准备菜单组件Menu或者PopupMenu(右击弹出子菜单),把第一步中准备好的菜单项组件添加进来;
3.准备菜单条组件MenuBar,把第二步中准备好的菜单组件Menu添加进来;
4.把第三步中准备好的菜单条组件添加到窗口对象中显示。
小技巧:
1.如果要在某个菜单的菜单项之间添加分割线,那么只需要调用Menu的add(new MenuItem(-))即可。
2.如果要给某个菜单项关联快捷键功能,那么只需要在创建菜单项对象时设置即可,例如给菜单项关联 ctrl+shif+/ 快捷键,只需要:new MenuItem("菜单项名字",new MenuShortcut(KeyEvent.VK_Q,true);
案例1:
使用awt中常用菜单组件,完成下图效果
演示代码1:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class SimpleMenu {
//创建窗口
private Frame frame = new Frame("这里测试菜单相关组件");
//创建菜单条组件
private MenuBar menuBar = new MenuBar();
//创建文件菜单组件
private Menu fileMenu = new Menu("文件");
//创建编辑菜单组件
private Menu editMenu = new Menu("编辑");
//创建新建菜单项
private MenuItem newItem = new MenuItem("新建");
//创建保存菜单项
private MenuItem saveItem = new MenuItem("保存");
//创建退出菜单项
private MenuItem exitItem = new MenuItem("退出");
//创建自动换行选择框菜单项
private CheckboxMenuItem autoWrap = new CheckboxMenuItem("自动换行");
//创建复制菜单项
private MenuItem copyItem = new MenuItem("复制");
//创建粘贴菜单项
private MenuItem pasteItem = new MenuItem("粘贴");
//创建格式菜单
private Menu formatMenu = new Menu("格式");
//创建注释菜单项
private MenuItem commentItem = new MenuItem("注释");
//创建取消注释菜单项
private MenuItem cancelItem = new MenuItem("取消注释");
//创建一个文本域
private TextArea ta = new TextArea(6, 40);
public void init(){
//定义菜单事件监听器
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
ta.append("单击“"+command+"”菜单n");
if (command.equals("退出")){
System.exit(0);
}
}
};
//为注释菜单项和退出菜单项注册监听器
commentItem.addActionListener(listener);
exitItem.addActionListener(listener);
//为文件菜单fileMenu添加菜单项
fileMenu.add(newItem);
fileMenu.add(saveItem);
fileMenu.add(exitItem);
//为编辑菜单editMenu添加菜单项
editMenu.add(autoWrap);
editMenu.add(copyItem);
editMenu.add(pasteItem);
//为格式化菜单formatMenu添加菜单项
formatMenu.add(commentItem);
formatMenu.add(cancelItem);
//将格式化菜单添加到编辑菜单中,作为二级菜单
editMenu.add(new MenuItem("-"));
editMenu.add(formatMenu);
//将文件菜单和编辑菜单添加到菜单条中
menuBar.add(fileMenu);
menuBar.add(editMenu);
//把菜单条设置到frame窗口上
frame.setMenuBar(menuBar);
//把文本域添加到frame中
frame.add(ta);
//设置frame最佳大小并可见
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new SimpleMenu().init();
}
}
案例2:
通过PopupMenu实现下图效果:
实现思路:
1.创建PopubMenu菜单组件;
2.创建多个MenuItem菜单项,并添加到PopupMenu中;
3.将PopupMenu添加到目标组件中;
4.为需要右击出现PopubMenu菜单的组件,注册鼠标监听事件,当监听到用户释放右键时,弹出菜单。
演示代码2:
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class PopupMenuTest {
private Frame frame = new Frame("这里测试PopupMenu");
//创建PopubMenu菜单
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("我爱中华!!!", 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 mouseReleased(MouseEvent e) {
boolean flag = e.isPopupTrigger();
//判断当前鼠标操作是不是触发PopupMenu的操作
if (flag){
//让PopupMenu显示在panel上,并且跟随鼠标事件发生的地方显示
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 PopupMenuTest().init();
}
}



