AWT/Swing——事件处理

前言

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

什么是事件

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

什么是事件处理

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

事件处理中的三要素

事件源:是这个对象的状态改变引起的事件,事件源一般是Component。编程语言

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

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

AWT中事件处理的流程

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

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

举例点击事件

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

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

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被点击了");
            }
        });
    }
}

运行结果图1
运行结果图2

AWT中事件处理的模板

class XXXXListener implements XXXListener {
    @Override 
    public void xxx(ActionEvent e) {
        System.out.println("用户单击了按钮");
    }
}
…
yyy.addXXXListener(new XXXXListener());

建立一个监听器类,该类实现监听器接口XXXListener,而后实现监听器方法使得能够处理对应事件3d

  • 在感兴趣的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表达式、使用设计模式的适配器思想去简化设置监听器的代码。在本身写的过程当中才会体会更多

相关文章
相关标签/搜索