第四十九讲 GUI(图形用户界面)
GUI的简单概述
Graphical User Interface(图形用户接口),用图形的方式,来显示计算机操作的界面,这样更方便更直观。与之相对应的Command line User Interface (命令行用户接口),就是常见的Dos命令行操作,需要记忆一些常用的命令,操作不直观。
Awt和Swing
Awt
概述
Java为GUI提供的对象都存在java.awt和javax.swing两个包中。java.awt就是Abstract Window ToolKit (抽象窗口工具包),需要调用本地系统方法实现功能,它属于重量级控件。
继承关系图
所有的可以显示出来的图形元素都称为Component,Component代表了所有的可见的图形元素,Component里面有一种比较特殊的图形元素叫Container,Container(容器)在图形界面里面是一种可以容纳其它Component元素的一种容器,Container本身也是一种Component,Container里面也可以容纳别的Container。
Container里面又分为Window和Panel,Window是可以独立显示出来的,平时我们看到的各种各样的应用程序的窗口都可以称为Window,Window作为一个应用程序窗口可以独立显示出来,Panel也可以容纳其它的图形元素,但一般看不见Panel,Panel不能作为应用程序的独立窗口显示出来,Panel要想显示出来就必须得把自己装入到Window里面才能显示出来。Panel应用比较典型的就是Applet(Java的页面小应用程序),现在基本上已经不用了,AJAX和JAVASCRIPT完全取代了它的应用;Window本身又可以分为Frame和Dialog,Frame就是我们平时看到的一般的窗口,而Dialog则是那些需要用户进行了某些操作(如点击某个下拉菜单的项)才出现的对话框,这种对话框就是Dialog。
布局管理器
容器中的组件的排放方式,就是布局。Awt提供了5种布局管理器类,它们依次是FlowLayout(流式布局管理器)、BorderLayout(边界布局管理器)、GridLayout(网格布局管理器)、GridBagLayout(网格包布局管理器)、CardLayout(卡片布局管理器),但是最屌的布局还是坐标式布局。下面分别对它们进行简单的介绍。
FlowLayout
FlowLayout是Panel类的默认布局管理器。FlowLayout布局管理器对组件逐行定位,行内从左到右,一行排满后换行,它不改变组件的大小,按组件原有尺寸显示组件,可设置不同的组件间距、行距以及对齐方式。FlowLayout布局管理器默认的对齐方式是居中。
BorderLayout
BorderLayout是Frame类的默认布局管理器。BorderLayout将整个容器的布局划分成东(EAST)、西(WEST)、南(SOUTH)、北(NORTH)、中(CENTER)五个区域,组件只能被添加到指定的区域。如不指定组件的加入部位,则默认加入到CENTER区。每个区域只能加入一个组件,如加入多个,则先前加入的会被覆盖。
BorderLayout型布局管理器尺寸缩放原则:北、南两个区域在水平方向缩放,东、西两个区域在垂直方向缩放,中部可以在两个方向上缩放。
GridLayout
GridLayout型布局管理器将空间划分成规则的矩形网格,每个单元格区域大小相等。组件被添加到每个单元格中,先从左到右添满一行后换行,再从上到下。
GridBagLayout
GridBagLayout型布局管理器将空间划分成非规则的矩形网格,每个单元格区域大小不一定相等。
CardLayout
CardLayout型布局管理器将整个容器的布局划分成几个选项卡,诸如下图这样。
Swing
概述
javax.swing是在Awt的基础上建立的一套图形界面系统,其中提供了更多的组件,而且完全由Java实现。它增强了移植性,属于轻量级控件。
事件监听机制
事件监听机制的组成
事件监听机制由下面几项组成:
- 事件源:就是java.awt包或者java.swing包中那些图形界面组件;
- 事件:每一个事件源都有自己特有的对应事件和共性事件(鼠标、键盘事件等);
- 监听器:将可以触发某一个事件的动作(不只一个动作)都封装到监听器中;
- 事件处理:引发事件后的处理方式。
注意:事件源、事件、监听器在Java中都已经定义好了,直接获取其对象来用就可以了,我们所要做的事情就是对产生的动作进行处理。
事件监听机制流程图
事件监听机制中所要明确的注意点:
- 确定事件源(容器或组件);
- 通过事件源对象的addXxxListener方法将监听器注册到该事件源上,该方法中接收XxxListener的子类对象,或者XxxListener的子类XxxAdapter的子类对象,一般用匿名内部类来表示。在覆盖方法的时候,方法的参数一般是XxxEvent类型的变量;
- 事件触发后会把事件打包成对象传递给该变量(其中包括事件源对象,通过getSource()或者getComponent()获取)。
按钮事件
现在想要用户点击按钮有效果,比如打印一句话。
思路:
- 确定事件源(按钮);
- 确定监听器,按钮添加监听器,按钮对象最清楚,到按钮对象中查找;
- 定义处理方式。
package cn.liayun.awt.frame;
import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class FrameSimple {
public static void main(String[] args) {
// 1,创建一个窗体,通过Frame
Frame f = new Frame("按钮事件");
// 2,对窗体进行基本设置
f.setSize(500, 400);
f.setLocation(400, 200);
f.setBackground(Color.blue);// 设置窗体的背景颜色
// blue是Color类里面的一个静态常量,可以使用"类名.静态常量名"来访问
// 设置布局
f.setLayout(new FlowLayout());
// 给窗体添加组件
Button but = new Button("my button");
// 将组件添加到窗体中
f.add(but);
/*
* 需求:想要用户点击按钮有效果,比如打印一句话
* 思路:
* 1,确定事件源(按钮);
* 2,确定监听器,按钮添加监听器,按钮对象最清楚,到按钮对象中查找;
* 3,定义处理方式。
*
* 定义的规范:XxxListener,Xxx监听器,有对应的XxxEvent事件。
*/
//1,在按钮上添加所需的监听器
but.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被触发了......" + e);
// System.exit(0);
}
});
// 3,让窗体显示
f.setVisible(true);
}
}
窗体事件
现在想要实现点击窗体的✗(关闭),就可以实现窗体的关闭。
package cn.liayun.awt.frame;
import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class FrameSimple {
public static void main(String[] args) {
// 1,创建一个窗体,通过Frame
Frame f = new Frame("按钮事件");
// 2,对窗体进行基本设置
f.setSize(500, 400);
f.setLocation(400, 200);
f.setBackground(Color.blue);// 设置窗体的背景颜色
// blue是Color类里面的一个静态常量,可以使用"类名.静态常量名"来访问
// 设置布局
f.setLayout(new FlowLayout());
// 给窗体添加组件
Button but = new Button("my button");
// 将组件添加到窗体中
f.add(but);
/*
* 需求:想要用户点击按钮有效果,比如打印一句话
* 思路:
* 1,确定事件源(按钮);
* 2,确定监听器,按钮添加监听器,按钮对象最清楚,到按钮对象中查找;
* 3,定义处理方式。
*
* 定义的规范:XxxListener,Xxx监听器,有对应的XxxEvent事件。
*/
//1,在按钮上添加所需的监听器
but.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被触发了......" + e);
// System.exit(0);
}
});
/*
* 需求:想要实现点击窗体的X,就可以实现窗体的关闭。
* 思路:
* 1,事件源:窗体;
* 2,监听器,通过窗体对象去查;
* 3,事件处理
*
* 到底哪些监听接口有适配器类?
* 只要监听接口中的方法在2个以内,都没有适配器类。适配器类的出现只为方便创建监听器对象。
* 但是一般监听接口都有适配器。
*/
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.out.println("window closing");
System.exit(0);
}
@Override
public void windowOpened(WindowEvent e) {
System.out.println("孔雀开屏!window open");
}
});
// 3,让窗体显示
f.setVisible(true);
}
}
只要监听接口中的方法在2个以内,都没有适配器类。适配器类的出现只为方便创建监听器对象,但是一般监听接口都有适配器。
鼠标事件
演示鼠标监听。按钮作为事件源,鼠标监听器注册到按钮上。
package cn.liayun.awt.frame;
import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class FrameSimple {
public static void main(String[] args) {
// 1,创建一个窗体,通过Frame
Frame f = new Frame("按钮事件");
// 2,对窗体进行基本设置
f.setSize(500, 400);
f.setLocation(400, 200);
f.setBackground(Color.blue);// 设置窗体的背景颜色
// blue是Color类里面的一个静态常量,可以使用"类名.静态常量名"来访问
// 设置布局
f.setLayout(new FlowLayout());
// 给窗体添加组件
Button but = new Button("my button");
// 将组件添加到窗体中
f.add(but);
/*
* 需求:想要用户点击按钮有效果,比如打印一句话
* 思路:
* 1,确定事件源(按钮);
* 2,确定监听器,按钮添加监听器,按钮对象最清楚,到按钮对象中查找;
* 3,定义处理方式。
*
* 定义的规范:XxxListener,Xxx监听器,有对应的XxxEvent事件。
*/
//1,在按钮上添加所需的监听器
but.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被触发了......" + e);
// System.exit(0);
}
});
/*
* 需求:想要实现点击窗体的X,就可以实现窗体的关闭。
* 思路:
* 1,事件源:窗体;
* 2,监听器,通过窗体对象去查;
* 3,事件处理
*
* 到底哪些监听接口有适配器类?
* 只要监听接口中的方法在2个以内,都没有适配器类。适配器类的出现只为方便创建监听器对象。
* 但是一般监听接口都有适配器。
*/
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.out.println("window closing");
System.exit(0);
}
@Override
public void windowOpened(WindowEvent e) {
System.out.println("孔雀开屏!window open");
}
});
/*
* 演示鼠标监听。
*
* 按钮作为事件源。
* 鼠标监听器注册到按钮上。
*
* 组件.addXxxListener(new XxxAdapter() {
* public void methodName(XxxEvent e) {}
* });
*/
but.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
/*
* 想要对鼠标双击进行处理。应该找鼠标事件对象,因为事件对象一产生,内部必然封装事件源以及事件相关内容。
* 要查MouseEvent对象。
*/
if (e.getClickCount() == 2) {
System.out.println("mouse double click");
}
}
});
// 3,让窗体显示
f.setVisible(true);
}
}
此时,不仅给按钮注册了一个ActionListener(活动监听器),还给按钮注册了一个MouseListener(鼠标监听器)。但要注意,按钮尽量添加ActionEvent(活动事件),当还有点击事件时,点击事件先执行。
键盘事件
文本框中只能输入数字。输入0-9之外的字符,提示输入非法,并且无法输入。
package cn.liayun.awt.frame;
import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class FrameSimple {
public static void main(String[] args) {
// 1,创建一个窗体,通过Frame
Frame f = new Frame("按钮事件");
// 2,对窗体进行基本设置
f.setSize(500, 400);
f.setLocation(400, 200);
f.setBackground(Color.blue);// 设置窗体的背景颜色
// blue是Color类里面的一个静态常量,可以使用"类名.静态常量名"来访问
// 设置布局
f.setLayout(new FlowLayout());
// 给窗体添加组件
Button but = new Button("my button");
//加入一个文本框组件
TextField tf = new TextField(40);
// 将组件添加到窗体中
f.add(but);
f.add(tf);
/*
* 需求:想要用户点击按钮有效果,比如打印一句话
* 思路:
* 1,确定事件源(按钮);
* 2,确定监听器,按钮添加监听器,按钮对象最清楚,到按钮对象中查找;
* 3,定义处理方式。
*
* 定义的规范:XxxListener,Xxx监听器,有对应的XxxEvent事件。
*/
//1,在按钮上添加所需的监听器
but.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被触发了......" + e);
// System.exit(0);
}
});
/*
* 需求:想要实现点击窗体的X,就可以实现窗体的关闭。
* 思路:
* 1,事件源:窗体;
* 2,监听器,通过窗体对象去查;
* 3,事件处理
*
* 到底哪些监听接口有适配器类?
* 只要监听接口中的方法在2个以内,都没有适配器类。适配器类的出现只为方便创建监听器对象。
* 但是一般监听接口都有适配器。
*/
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.out.println("window closing");
System.exit(0);
}
@Override
public void windowOpened(WindowEvent e) {
System.out.println("孔雀开屏!window open");
}
});
/*
* 演示鼠标监听。
*
* 按钮作为事件源。
* 鼠标监听器注册到按钮上。
*
* 组件.addXxxListener(new XxxAdapter() {
* public void methodName(XxxEvent e) {}
* });
*/
but.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
/*
* 想要对鼠标双击进行处理。应该找鼠标事件对象,因为事件对象一产生,内部必然封装事件源以及事件相关内容。
* 要查MouseEvent对象。
*/
if (e.getClickCount() == 2) {
System.out.println("mouse double click");
}
}
});
/*
* 需求:文本框中只能输入数字。
* 事件源:文本框。
* 文本框注册键盘监听。
* 事件处理。
*/
tf.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
//1,如何获取录入的内容?通过键盘事件获取。
// char key = e.getKeyChar();
// int code = e.getKeyCode();
// System.out.println(code + "..." + KeyEvent.getKeyText(code));
int code = e.getKeyCode();
if (!(code >= KeyEvent.VK_0 && code <= KeyEvent.VK_9)) {
System.out.println("必须是0-9之间的数字");
e.consume();//直接取消默认处理方式
}
//组合键的应用
// if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER) {
// System.out.println("ctrl + enter run");
// }
}
});
// 3,让窗体显示
f.setVisible(true);
}
}