AWT/Swing——事件处理
前言
当用户点击图形界面上的一个按钮或者其他Component时要有所响应,这才是实现了图形界面的交互功能。如何做出这些响应我们就需要了解事件的处理机制。下面将分为以下内容介绍AWT(Swing)中事件处理机制:
什么是事件
通俗一点来说就是某种状态的改变,在我们的图形界面中就表现为某个按钮被点击了,窗口被关闭了等。
什么是事件处理
当某个事件发生时(界面中的某个Component的某个状态发生改变时),我们希望在这个时机执行一些代码来做我们希望做的事,这个就是事件处理。如点击窗口关闭按钮时,弹出对话框询问用户是否保存当前已经修改过的内容。
Java是面向对象的编程语言,Java中使用监听器类来探测一个事件(改变),使用监听器类中的方法来在事件发生的时候处理事件。
事件处理中的三要素
事件源:是这个对象的状态改变引发的事件,事件源通常是Component。
事件:事件源发生的状态改变。如按钮被鼠标左击或者被鼠标右击等。
事件监听器:监听器被安装在某个Component上,负责监听这个Component具体状态被改变了。
AWT中事件处理的流程
外部诱使事件源状态发生变化,产生事件对象,然后事件监听器监听到该事件的发生,做出响应。
- 首先将事件监听器注册到事件源上面
- 触发事件源上的事件(改变状态)
- 生成事件对象
- 事件监听器监听到该事件的发生,生成的事件对象当做参数传入事件处理器(监听器类中的方法)
- 调用事件处理器做出响应
举例点击事件
鼠标点击按钮后,文本框中显示一行‘按钮被点击了'。
先是在按钮上注册了事件监听器,监听器中设置鼠标被点击时应该调用的事件处理器是怎么处理的;然后,鼠标点击按钮;生成按钮被点击的事件对象;事件监听器监听到点击事件发生,就会传入事件对象到事件处理器;最后,调用事件处理器中做出希望的响应。
public class TestEvent {
public static void main(String[] args) {
JFrame myFrame = new JFrame();
JButton btn = new JButton("点击我");
JTextField field = new JTextField();
//为field指定宽高
field.setPreferredSize(new Dimension(100, 40));
//使用Jpanel容器装载JButton和JTextFiedl组件
JPanel jPanel = new JPanel();
jPanel.add(btn);
jPanel.add(field);
myFrame.add(jPanel);
//设置窗口的大小宽高都为300像素以及位置距离屏幕左上方向右300像素以及向下300像素
myFrame.setBounds(300, 300, 300, 300);
//必须设置这个属性 才可以看见窗口
myFrame.setVisible(true);
//为btn设置事件监听器 监听器采用匿名内部类的形式
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
field.setText("Button被点击了");
}
});
}
}
AWT中事件处理的模板
class XXXXListener implements XXXListener {
@Override
public void xxx(ActionEvent e) {
System.out.println("用户单击了按钮");
}
}
…
yyy.addXXXListener(new XXXXListener());
创建一个监听器类,该类实现监听器接口XXXListener
,然后实现监听器方法使得可以处理对应事件
在感兴趣的Component上使用
addXXXListener(...)
,添加监听器即传入监听器的实例注意:
不同的Component有不同的事件发生,但是一般添加监听器的方法都是
addXXXListener(...)
。Component会有不同的事件发生,所以需要对感兴趣的事件添加对应的监听器。有些监听器内部会有多个方法,可以监听多种事件,但是这些事件一般都相关。在点击事件举例中,我们添加监听器采用的匿名内部类的形式,可以看出监听器的实现形式还是有多种。
监听器(EventListener)的实现形式
监听器是一种特殊的Java类。在AWT中,监听器主要有以下几种实现方式:
监听器作为外部类
规范易于理解、类本身可以重用;不足在于一般情况下不利于实现事件处理中的功能,因为不易于访问界面中的属性和方法
class BtnListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
//使用getSource获取事件源对象 但是不易访问到其他组件
JButton btn = (JButton)e.getSource();
btn.setText("我被点击了");
}
}
public class TestListener {
private JFrame myFrame = new JFrame("测试外部监听器");
private JButton btn = new JButton("点击我");
private JTextField field = new JTextField();
//构造函数
public TestListener() {
init();
}
//初始化 为按钮添加事件监听器
public void init() {
JPanel jPanel = new JPanel();
jPanel.add(btn);
field.setPreferredSize(new Dimension(100, 40));
jPanel.add(field);
//以创建外部类对象方式添加事件监听器
btn.addActionListener(new BtnListener());
myFrame.add(jPanel);
myFrame.setBounds(300, 300, 500, 300);
//使得按钮窗口的关闭按钮可以关闭窗口
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//显示窗口
public void showFrame() {
myFrame.setVisible(true);
}
public static void main(String[] args) {
new TestListener().showFrame();
}
}
监听器作为内部类
可以方便的访问主类中的任何属性和方法,包括私有方法;不足在于使得主类过于复杂、不可以在不同界面中重用
public class TestListener {
//内部类
class BtnListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
//可以方便操作主类的其他属性
field.setText("Btn被点击了");
}
}
...
//初始化 为按钮添加事件监听器
public void init() {
...
//以创建内部类对象方式添加事件监听器
btn.addActionListener(new BtnListener());
...
}
...
}
监听器作为主类本身
可以方便地访问本类中的任何方法和属性;不足在于使得本类的方法过多
//主类作为监听器
public class TestListener implements ActionListener{
private JFrame myFrame = new JFrame("测试主类作为监听器");
private JButton btn = new JButton("点击我");
private JTextField field = new JTextField();
//构造函数
public TestListener() {
init();
}
//实现的处理方法
@Override
public void actionPerformed(ActionEvent e) {
field.setText("Btn被点击了");
}
//初始化 为按钮添加事件监听器
public void init() {
JPanel jPanel = new JPanel();
jPanel.add(btn);
field.setPreferredSize(new Dimension(100, 40));
jPanel.add(field);
//主类本身作为监听器对象传入
btn.addActionListener(this);
myFrame.add(jPanel);
myFrame.setBounds(300, 300, 500, 300);
//使得按钮窗口的关闭按钮可以关闭窗口
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//显示窗口
public void showFrame() {
myFrame.setVisible(true);
}
public static void main(String[] args) {
new TestListener().showFrame();
}
}
监听器作为匿名内部类
可以方便地访问主类的方法和属性;不足在于对于每个事件都需要写匿名内部类,不能重用、不利于理解
//主类作为监听器
public class TestListener{
private JFrame myFrame = new JFrame("测试主类作为监听器");
private JButton btn = new JButton("点击我");
private JTextField field = new JTextField();
//构造函数
public TestListener() {
init();
}
//初始化 为按钮添加事件监听器
public void init() {
JPanel jPanel = new JPanel();
jPanel.add(btn);
field.setPreferredSize(new Dimension(100, 40));
jPanel.add(field);
//以匿名内部类的方式创建监听器
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
field.setText("Btn被点击了");
}
});
//或者使用lambda表达式
// btn.addActionListener(event->field.setText("Btn被点击了"));
myFrame.add(jPanel);
myFrame.setBounds(300, 300, 500, 300);
//使得按钮窗口的关闭按钮可以关闭窗口
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//显示窗口
public void showFrame() {
myFrame.setVisible(true);
}
public static void main(String[] args) {
new TestListener().showFrame();
}
}
关于使用lambda表达式的理解:若某个方法使用的类是“众所周知“的并且类中的方法是唯一的,我们就只需要给出参数和一些执行代码代替原来复杂的一堆代码。因为唯一性,编译器就会推断出使用的是什么类以及类中的方法。
上面我们可以使用lamnda表达式event->field.setText(...)
代替了匿名内部类那么多代码,那是因为编译器可以推断出addListener(...)
需要传入的参数是实现了ActionListener
接口的类,这个类中有唯一的方法就是actionPerformed
以及这个方法只有一个参数而且也知道其参数类型。
使用lambda表达式虽然可以简化我们的代码,但是我们需要理清楚其原本应该使用什么类以及什么方法。
若是省略的方法由多个参数则->
左边的参数需要使用()
括起来如(a,b,c)
,->
后有多行需要执行的代码则使用{}
将代码括起来。
事件适配器(EventAdapter)
我们在创建监听器类时需要实现其实现的相应监听器接口中的所有方法。前面提到过,某些监听器接口内会有多个方法,但是我们只对一些方法感兴趣,有没有方法只用实现感兴趣的方法其他方法就不实现呢。答案是有的,那就是使用事件适配器。Java内部已经帮我们事先写了一些适配器,我们只需要实现感兴趣的适配器,然后重写我们感兴趣的方法。
若是没有适配器,我们想监听鼠标点击事件,我们先看MouseListener接口的源码实现:
public interface MouseListener extends EventListener {
/**
* Invoked when the mouse button has been clicked (pressed
* and released) on a component.
*/
public void mouseClicked(MouseEvent e);
/**
* Invoked when a mouse button has been pressed on a component.
*/
public void mousePressed(MouseEvent e);
/**
* Invoked when a mouse button has been released on a component.
*/
public void mouseReleased(MouseEvent e);
/**
* Invoked when the mouse enters a component.
*/
public void mouseEntered(MouseEvent e);
/**
* Invoked when the mouse exits a component.
*/
public void mouseExited(MouseEvent e);
}
我们需要实现mouseClicked方法以外的其他4个方法,可以说是非常麻烦的。我们再看MouseAdapter的源码实现:
public abstract class MouseAdapter implements MouseListener, MouseWheelListener, MouseMotionListener {
/**
* {@inheritDoc}
*/
public void mouseClicked(MouseEvent e) {}
/**
* {@inheritDoc}
*/
public void mousePressed(MouseEvent e) {}
/**
* {@inheritDoc}
*/
public void mouseReleased(MouseEvent e) {}
/**
* {@inheritDoc}
*/
public void mouseEntered(MouseEvent e) {}
/**
* {@inheritDoc}
*/
public void mouseExited(MouseEvent e) {}
/**
* {@inheritDoc}
* @since 1.6
*/
public void mouseWheelMoved(MouseWheelEvent e){}
/**
* {@inheritDoc}
* @since 1.6
*/
public void mouseDragged(MouseEvent e){}
/**
* {@inheritDoc}
* @since 1.6
*/
public void mouseMoved(MouseEvent e){}
}
可以看出适配器的实现非常巧妙,为每个方法添加一个空的方法体而为我们进行一次封装,我们只需重写我们感兴趣的方法就可,其他方法也不会受到影响。
AWT中的事件分类
AWT中的事件主要分为两大类:低级事件和高级事件
低级事件
低级事件就比较底层(比较细节),主要有:
ComponentEvent:组件事件,当组件尺寸发生改变、位置发生变化、显示/隐藏状态发生改变时,就会触发该事件
ContainerEvent:容器事件,当容器里增加、删除组件时,就会触发该事件
WindowEvent:窗口事件,当窗口状态发生改变(打开、关闭、最大化、最小化)时,就会触发该事件
FocusEvent:焦点事件,当组件得到焦点或者失去焦点时,就会触发该事件
KeyEvent:键盘事件,当键盘按键被按下、松开时就会触发该事件
MouseEvent:鼠标事件,当一个组件被鼠标按下、放开、在其上面移动鼠标时,就会触发该事件
PaintEvent:绘制事件,当GUI组件调用update()/paint()方法时触发该事件,该事件并非专用于事件处理模型中,一般也很少直接监听该事件
高级事件
高级事件基于语义,并不和特定的动作相关,而依赖于触发该事件的组件类别。主要分为:
- ActionEvent:动作事件,当按钮、菜单等能产生Action的项目被单击,或者在TextField中按下Enter按钮时,就会触发该事件
- AdjustmentEvent:调节事件,在滑动条上移动滑块调节数值时触发该事件
- ItemEvent:–选项事件,当在有很多项目的组件中,选中或者取消选中了某一个项目,就会触发该事件
- TextEvent:文本事件,当文本框或者文本域这类具有文本的组件中,文本发生变化时,就会触发该事件
小结
总结了关于事件处理的大部分基础,基础概念有了,重要的还是多写代码实践。另外事件处理中还是涉及到很多技巧,比如使用lambda表达式、使用设计模式的适配器思想去简化设置监听器的代码。在自己写的过程中才会体会更多
AWT/Swing——事件处理的更多相关文章
- 编写Java程序,使用Swing事件处理机制实现用户登录和英雄信息显示
返回本章节 返回作业目录 需求说明: 使用Swing事件处理机制实现用户登录和英雄信息显示 实现思路: 创建LoginView类,该类用于显示登录界面,为登录按钮添加ActionListener事件, ...
- Java Swing事件处理机制
Java Swing的事件处理机制 Swing GUI启动后,Java虚拟机就启动三个线程,分别为主线程,事件派发线程(也是事件处理线程)和系统工具包线程. 主线程 :负责创建并显示该程序的初始界面: ...
- Java——Swing事件处理
import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import javax.swing.JFrame; ...
- 【java图形计算器】 java awt swing组件应用
package package1; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swi ...
- AWT初步— 事件处理模型
之前学习的内容只能形成一个用户界面,而用户不能对其有实际的操作,也就是说用户界面没有任何功能.要能够让图形界面接收用户的操作,就必须给各个组件加上事件处理机制.在事件处理的过程中,主要涉及三类对象: ...
- Java GUI编程中AWT/swing/SWT的优缺点
http://www.cnblogs.com/dugang/archive/2010/10/22/1858478.html AWT AWT是Abstract Window Toolkit(抽象窗口工具 ...
- Awt & Swing
AWT 是抽象窗口组件工具包,是 java 最早的用于编写图形节目应用程序的开发包. Swing 是为了解决 AWT 存在的问题而新开发的包,它以 AWT 为基础的. 具体的说就是: AWT 是Abs ...
- 转存下链接--- Java awt Swing 进行拖拽实现布局
http://blog.csdn.net/vpingchangxin/article/details/8673825 swing开发图形界面工具,eclipse swing图形化操作界面工具配置
- AWT,Swing,RCP 开发
http://www.blogjava.net/youxia/category/17374.html
随机推荐
- 学以致用三十六-----弄懂python装饰器
看了海峰老师讲解的装饰器视频,讲解的非常棒.根据视频,记录笔记如下: 装饰器: 1.本质是函数,用def来定义.功能就是用来(装饰)其他函数,为其他函数添加附加功能 现有两个函数如下, def tes ...
- Python request库与爬虫框架
Requests库的7个主要方法 requests.request():构造一个请求,支持以下各方法的基础方法 requests.get():获取HTML网页的主要方法,对应于HTTP的GET ...
- noip第32课资料
- Oracle 12c client with .NET legacy Oracle driver
如果使用Oracle 12c Client和.NET的Oracle driver,你很可能会碰到跟下面一样的问题: https://www.codeproject.com/Questions/8767 ...
- OC协议、代理的简单使用
在不同类之间传递数据,我所学到的有三种,1.代理,2.block,3.通知.在这里,我们先来讲一下代理的使用,后面我会继续讲到block和通知.代理通常和协议是一起使用的,协议通常写在代理类里面,被代 ...
- future项目上报
private String name;//预警名称 private String detail;//详细 用于定义位置和报错信息,越多越好private String code;//编码 1001是 ...
- ansible 关闭ssh首次连接时提示
关闭ssh首次连接时提示. 修改/etc/ansible/ansible.cfg配置文件 方法一:(推荐,配置文件中存在) host_key_checking = False 方法二: ssh_arg ...
- Openvswitch手册(2): OpenFlow Controller
我们这一节主要来看Controller Controller有两种: Primary Controller: 真正控制vswitch的flow table,vswitch会保持和contro ...
- SpringDataJPA
看着自己弟弟在成都聚全家之力盘一套房, 看着自己二哥,在成都也为车贷房贷奔波劳累,身心俱惫, 生活不易啊,这个社会环境下,就像从数据库拿数据一样,只拿我们想要的,或许会活的滋润很多吧. 最近的这个项目 ...
- 初探系列 — Pharbers用于单点登录的权限架构
一. 前言 就职公司 法伯科技是一家以数据科技为驱动, 专注于医药健康领域的循证咨询公司. 以数据科学家身份, 赋能医药行业. 让每位客户都能享受数据带来的价值, 洞察业务, 不止于数据, 让决策更精 ...