从JDK1.1开始,Java采用了一种名为“委托事件模型”的事件处理机制,以支持Java GUI程序与用户的实时交互。
java事件和事件处理机制
- 委托事件模型
- 事件(Event):用户在GUI组件上进行的操作,如鼠标单击、输入文字、关闭窗口等。 时间类对象用于描述发生了什么事情。
约定:组件在与用户交互时,遇到特定操作则会触发相应的事件,即自动创建事件类对象并提交给Java运行时系统 - 事件源(Event Source):能够产生事件的GUI组件对象,如按钮、文本框等。
- 事件处理方法(Event Handler):能够接收、解析和处理事件类对象,实现与用户交互功能的方法。
- 事件监听器(Event Listener):调用事件处理方法的对象。实现相应
- 时间源产生事件,处理方法属于事件监听器
- 系统在接受到事件类对象后,立即将其发送给专门的事件处理对象(监听器),该对象调用其事件处理r 方法,处理先前的事件类对象,进而实现预期的事件处理逻辑。
import java.awt.*;
//事件监听器
import java.awt.event.*;
class MyEventListener implements ActionListener{
//事件处理方法
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被按下 ");
}
}
public class ActionEventDemo {
public static void main(String[] args){
Frame f = new Frame("事件处理");
//事件源
Button b = new Button("按钮");
//监听器对象
MyEventListener m = new MyEventListener();
//注册事件监听
b.addActionListener(m);
f.setLayout(new FlowLayout());
f.add(b);
f.setSize(200,300);
f.setVisible(true);
}
}
- 按一下,控制台显示一下
import java.awt.*;
import java.awt.event.*;
public class ActionEventDemo2 extends Frame{
Label l;
Button b;
public ActionEventDemo2(){
super("时间处理");
b = new Button("按钮");
l = new Label("你好");
MyEventListener m = new MyEventListener();
b.addActionListener(m);
setLayout(new FlowLayout());
add(b);
add(l);
setSize(200,300);
setVisible(true);
}
public static void main(String[] args){
new ActionEventDemo2();
}
class MyEventListener implements ActionListener
{
public void actionPerformed(ActionEvent e) {
l.setText("大家好");
}
}
}
- 按按钮,你好变大家好
事件类:
- Java GUI主要事件类的层次结构:
- 低级事件:
- ComponentEvent(组件事件):组件尺寸的变化和移动
- ContainerEvent(容器事件):组件增加、移动
- WindowEvent(窗口事件):窗口闭合、图标化
- FocusEvent(焦点事件):焦点的获得和丢失
- KeyEvent(键盘事件):按钮被按下或释放
- MouseEven(鼠标事件):鼠标单机、双击、移动
- 高级事件
- ActionEvent(动作):按钮被按下、在文本框中按Enter键
- AdjustmentEvent:(调整)在滚动条上移动滑块
- ItemEvent(项目):选择项目
- TextEvent(文本):文本对象发生改变
监听接口:
- 只有实现了这些接口的类对象才有资格作监听器,去处理相应类型的事件。
- 事件监听器类型和对应的事件处理方法都是事先约定好的。所有事件处理方法的返回值类型均为void
- 一个事件源可以注册多个不同的监听器
- AWT组件极其可注册的监听器类型
事件适配器:
import java.awt.*;
import java.awt.event.*;
public class CloseDemo extends Frame{
Button b;
public CloseDemo(){
super("关闭窗口");
b = new Button("按钮");
setBackground(Color.yellow);
setBounds(100, 200, 300, 200);
add(b);
setVisible(true);
setLayout(new FlowLayout());
MyEvenListener m = new MyEvenListener();
b.addActionListener(m);
WindowHanlder w = new WindowHanlder();
addWindowListener(w);
}
public static void main(String[] args) {
new CloseDemo();
}
}
class MyEvenListener implements ActionListener{
public void actionPerformed(ActionEvent arg0) {
System.out.println("anxia");
}
}
class WindowHanlder implements WindowListener{
@Override
public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowClosed(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
@Override
public void windowDeactivated(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowDeiconified(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowIconified(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowOpened(WindowEvent e) {
// TODO Auto-generated method stub
}
}
点击按钮,按钮被按下;点击关闭按钮,窗口关闭
存在的问题:WindowHandler作为监听器类要处理“关闭”窗口动作,需要实现WindowListener接口,虽然只是用到一个相应的事件处理方法,但却不得不重写该接口中所有的7个抽象方法。
为简化程序员的编程负担,JDK中针对大多数事件监听器接口提供了相应的实现类(事件适配器Adapter),在适配器中,实现了相应监听器接口的所有方法,但不做任何处理,即只是添加了一个空的方法体。
WindowAdapter适配器的定义:
package java.awt.event;
public abstract class WindowAdapter implements WindowListener{
void windowClosing(WindowEvent){}
void windowOpened(WindowEvent e){}
void windowIconified(WindowEvent e){}
void windowDeiconified(WindowEvent e){}
void windowClosed(WindowEvent e){}
void windowActivated(WindowEvent e){}
void windowDeactivated(WindowEvent e){}
}
程序员在定义监听器类时就可以不再直接实现监听接口,而是继承事件适配器类,并只重写所需要的方法即可。
使用适配器类的优点:不用实现WindowListener接口中所有的抽象方法,需要哪个方法,重写哪个方法即可
但需注意:适配器类并不能完全取代相应的监听器接口,由于Java 单继承机制的限制,如果要定义的监听器类需要同时处理两种以上的GUI事件,则只能直接实现有关的监听器接口,而无法只通过继承适配器实现
改进的关闭窗口事件
import java.awt.*;import java.awt.event.*;
public class CloseDemox extends Frame {
public CloseDemox(){
super("关闭窗口");
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
setBounds(200,200,100,100);
setVisible(true);
}
public static void main(String[] args) {
new CloseDemox();
}
}
同上
import java.awt.*;import java.awt.event.*;
public class TestClose extends Frame {
public TestClose(){
super("关闭联系");
Button b = new Button("关闭");
MyEventListener m = new MyEventListener();
b.addActionListener(m);
setLayout(new FlowLayout());
add(b);
setSize(200,300);
setVisible(true);
}
public static void main(String[] args){
new TestClose();
}
class MyEventListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
}
内部类和匿名类在GUI 事件处理中的作用
- 内部类 在Java GUI 事件处理中,经常采用内部类来定义监听器类,这是因为监听器类中封装的业务逻辑具有非常强的针对性,通常没有重用价值。而且作为内部类的监听器对象可以直接访问外部类中的成员,这可以提供很大的便利。
import java.awt.*;
import java.awt.event.*;
public class InnerDemo extends Frame{
TextField tDisplay = new TextField(10);
Label l = new Label("请按下鼠标左键并拖动鼠标");
public InnerDemo(){
super("内部类测试");
add(l,"North");
add(tDisplay,"South");
InnerMonitor im = new InnerMonitor();
addMouseMotionListener(im);
addMouseListener(im);
setBackground(Color.pink);
setSize(300,200);
setVisible(true);
}
private class InnerMonitor implements MouseMotionListener,MouseListener{
public void mouseDragged(MouseEvent e) {
String s = "鼠标拖动到位置("+e.getX()+","+e.getY()+")";
tDisplay.setText(s);
}
public void mouseEntered(MouseEvent e) {
String s = "鼠标已进入窗体";
tDisplay.setText(s);
}
public void mouseExited(MouseEvent e) {
String s = "鼠标已移出窗体";
tDisplay.setText(s);
}
public void mouseClicked(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseMoved(MouseEvent arg0) {}
}
public static void main(String[] args) {
new InnerDemo();
}
}
- 鼠标在粉框里面显示“鼠标进入窗体”。
- 匿名内部类
import java.awt.*;
import java.awt.event.*;
public class AnonymousMonitorDemo extends Frame{
TextField tDisplay = new TextField(30);
Label l = new Label("请按下鼠标左键并拖动鼠标");
public AnonymousMonitorDemo(){
super("匿名内部类测试");
add(l,"North");
add(tDisplay,"South");
addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
tDisplay.setText("鼠标位置"+e.getPoint());
}
});
setBackground(Color.pink);
setSize(300,200);
setVisible(true);
}
public static void main(String[] args) {
new InnerDemo();
}
}
- 同上
多重监听:
- 由于事件源可以产生多种不同类型的事件,因而可以注册多种不同类型的监听器,但是当事件源发生了某种类型的事件时,只触发事先已就该种事件类型注册过的监听器。
- 事件源组件和监听器对象的对应关系:
- 针对同一个事件源组件的同一种事件也可以注册多个监听器。
- 针对同一个事件源组件的多种事件也可以注册同一个监听器对象进行处置。只是这要求监听器对象是一个“多面手”,即有能力处理各种不同类型的事件
- 同一个监听器对象可以被同时注册到多个不同的事件源上。
import java.awt.*;
import java.awt.event.*;
public class MultiListenerDemo extends Frame implements ActionListener {
Label l;
Button b1,b2;
Panel p;
public MultiListenerDemo(){
super("多重监听器");
l = new Label("没有任何按钮被按下");
b1 = new Button("Start");
b2 = new Button("Stop");
p = new Panel();
add(l,"North");
add(p,"South");
p.add(b1);
p.add(b2);
b1.addActionListener(this);
b2.addActionListener(this);
setSize(300,200);
setVisible(true);
}
public void actionPerformed(ActionEvent e){
if(e.getActionCommand().equals("Start")){
l.setText("Start被按下");
}else{
l.setText("Stop被按下");
}
}
public static void main(String[] args) {
new MultiListenerDemo();
}
}