前言

当用户点击图形界面上的一个按钮或者其他Component时要有所响应,这才是实现了图形界面的交互功能。如何做出这些响应我们就需要了解事件的处理机制。下面将分为以下内容介绍AWT(Swing)中事件处理机制:

什么是事件

通俗一点来说就是某种状态的改变,在我们的图形界面中就表现为某个按钮被点击了,窗口被关闭了等。

什么是事件处理

当某个事件发生时(界面中的某个Component的某个状态发生改变时),我们希望在这个时机执行一些代码来做我们希望做的事,这个就是事件处理。如点击窗口关闭按钮时,弹出对话框询问用户是否保存当前已经修改过的内容。
Java是面向对象的编程语言,Java中使用监听器类来探测一个事件(改变),使用监听器类中的方法来在事件发生的时候处理事件

事件处理中的三要素

事件源:是这个对象的状态改变引发的事件,事件源通常是Component。

事件:事件源发生的状态改变。如按钮被鼠标左击或者被鼠标右击等。

事件监听器:监听器被安装在某个Component上,负责监听这个Component具体状态被改变了。

AWT中事件处理的流程

外部诱使事件源状态发生变化,产生事件对象,然后事件监听器监听到该事件的发生,做出响应。

  1. 首先将事件监听器注册到事件源上面
  2. 触发事件源上的事件(改变状态)
  3. 生成事件对象
  4. 事件监听器监听到该事件的发生,生成的事件对象当做参数传入事件处理器(监听器类中的方法)
  5. 调用事件处理器做出响应

举例点击事件

鼠标点击按钮后,文本框中显示一行‘按钮被点击了'。

先是在按钮上注册了事件监听器,监听器中设置鼠标被点击时应该调用的事件处理器是怎么处理的;然后,鼠标点击按钮;生成按钮被点击的事件对象;事件监听器监听到点击事件发生,就会传入事件对象到事件处理器;最后,调用事件处理器中做出希望的响应。

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——事件处理的更多相关文章

  1. 编写Java程序,使用Swing事件处理机制实现用户登录和英雄信息显示

    返回本章节 返回作业目录 需求说明: 使用Swing事件处理机制实现用户登录和英雄信息显示 实现思路: 创建LoginView类,该类用于显示登录界面,为登录按钮添加ActionListener事件, ...

  2. Java Swing事件处理机制

    Java Swing的事件处理机制 Swing GUI启动后,Java虚拟机就启动三个线程,分别为主线程,事件派发线程(也是事件处理线程)和系统工具包线程. 主线程 :负责创建并显示该程序的初始界面: ...

  3. Java——Swing事件处理

    import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import javax.swing.JFrame; ...

  4. 【java图形计算器】 java awt swing组件应用

    package package1; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swi ...

  5. AWT初步— 事件处理模型

    之前学习的内容只能形成一个用户界面,而用户不能对其有实际的操作,也就是说用户界面没有任何功能.要能够让图形界面接收用户的操作,就必须给各个组件加上事件处理机制.在事件处理的过程中,主要涉及三类对象: ...

  6. Java GUI编程中AWT/swing/SWT的优缺点

    http://www.cnblogs.com/dugang/archive/2010/10/22/1858478.html AWT AWT是Abstract Window Toolkit(抽象窗口工具 ...

  7. Awt & Swing

    AWT 是抽象窗口组件工具包,是 java 最早的用于编写图形节目应用程序的开发包. Swing 是为了解决 AWT 存在的问题而新开发的包,它以 AWT 为基础的. 具体的说就是: AWT 是Abs ...

  8. 转存下链接--- Java awt Swing 进行拖拽实现布局

    http://blog.csdn.net/vpingchangxin/article/details/8673825 swing开发图形界面工具,eclipse swing图形化操作界面工具配置

  9. AWT,Swing,RCP 开发

    http://www.blogjava.net/youxia/category/17374.html

随机推荐

  1. gulp使用入门

    介绍:Gulp 是基于node.js的一个前端自动化构建工具,可以使用它构建自动化工作流程(前端集成开发环境):不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成,大大 ...

  2. mysql无密码登陆

    mysql登陆不上或者密码忘记可以尝试一下无密码登陆 以下一波神操作!! 首先关闭数据库服务(数据库在Centos7版本以上或者Redhat版本上被改名为mariadb) systemctl stop ...

  3. ssh框架 基本整合

    struts的基本配置 <struts> <constant name="struts.devModel" value="true" /> ...

  4. [转] An Introduction to Mutual SSL Authentication

    1. Introduction Mutual SSL authentication or certificate based mutual authentication refers to two p ...

  5. C++的学习心得

    由于我们大一就学习的c++,跳过了c语言,VB的学习,在很多方面我们掌握的并不是特别好,在这几种语言中,几乎有时候会产生混淆,通过做大量的c++的题目感觉在题目中应用的最多的就是数组.指针.对类的应用 ...

  6. Nuget4.0 bug一粒

    这个锅到底是nuget的还是msbuild的我也不是很确定 在使用Nuget4.0打包编译项目时 当执行到nuget pack %%~dpna.csproj -build -Prop Configur ...

  7. nginx关于限制请求数和连接数

    nginx轻巧功能强大,能承受几百并发量,ddos攻击几乎没有影响到nginx自身的工作,但是,太多的请求就开始影响后端服务了.所以必须要在nginx做相应的限制,让攻击没有到后端的服务器.这里阐述的 ...

  8. Spring Boot 2 - 使用CommandLineRunner与ApplicationRunner

    本篇文章我们将探讨CommandLineRunner和ApplicationRunner的使用. 在阅读本篇文章之前,你可以新建一个工程,写一些关于本篇内容代码,这样会加深你对本文内容的理解,关于如何 ...

  9. SpringMVC 全局异常处理

    在 JavaEE 项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的.不可预知的异常需要处理.每个过程都单独处理异常,系统的代码耦合度 ...

  10. 基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)

    1.前言 本文要分享的消息推送指的是当iOS端APP被关闭或者处于后台时,还能收到消息/信息/指令的能力. 这种在APP处于后台或关闭情况下的消息推送能力,通常在以下场景下非常有用: 1)IM即时通讯 ...