事件驱动程序设计

来源:互联网 发布:datagridview添加数据 编辑:程序博客网 时间:2024/05/01 23:47

事件和事件源

运行java图形用户界面程序时,程序与用户进行交互,事件驱动程序的执行.事件(event)可以定义为程序发生了某些事情的信号.外部用户动作和内部程序动作都可以触发事件,外部用户动作的例子有移动鼠标,点击按钮和敲击键盘等,而内部程序动作的例子有定时器.程序可以选择响应事件或忽略事件.
能创建一个事件并触发该事件的组件称为源对象(source object)源组件(source component).例如,按钮是按钮点击动作事件的源对象.一个事件是事件类的实例.事件类的根类是java.util.EventObject.
这里写图片描述
事件对象包含与事物相关的一切属性.可以使用EventObject类中的实例方法getSource()获得事件的源对象.EventObject类的子类处理特定类型的事件,例如,动作事件,窗口事件,组件事件,鼠标事件以及按键事件.
外部动作用户,源对象和事件类型
这里写图片描述
注意:如果一个组件可以触发某个事件,那么这个组件的任意子类都可以触发同类型的事件.例如,每个GUI组件都可以触发MouseEvent,KeyEvent,FocusEventComponentEvent,因为Component是所有GUI组件的父类.
注意:上图除了ListSelectionEventChangeEvent之外的所有事件类都包括在java.awt.event包中,ListSelectionEventChangeEventjavax.swing.event包中.AWT是为AWT组件设计的,但是许多Swing组件都会触发它们.

监听器,注册以及处理事件

Java使用一种基于委托的模型来处理事件:源对象触发一个事件,对此事件感兴趣的对象会处理它.将对此事件感兴趣的对象称为监听器(listener).一个对象要成为源对象上的事件监听器,需要具备两个条件:
这里写图片描述
这里写图片描述
1.监听器对象的类必须是相应的事件监听器接口的实例,以确保监听器有处理这个事件的正确方法.Java为每一种类型的事件都提供个监听器接口.通常,事件XEvent的监听器接口命名为XListener,监听器MouseMotionListener例外.例如,事件ActionEvent对应的监听器接口是ActionListener,ActionEvent的每个监听器都因该实现ActionListener接口.事件类型,对应的监听器接口以及定义在监听器接口中的方法.包含处理事件的监听器接口称为处理器(handler)的方法.
2.监听器对象必须由源对象注册.注册方法依赖与事件的类型.如果事件类型是ActionEvent,那么对应的注册方法是addActionListener.一般来说,XEvent的注册方法命名为addXListener.一个源对象可以触发几种类型的事件.一个源对象针对每个事件都维护着一个注册的监听器列表,通过调用监听器对象上的处理器来通知所有注册的监听器响应这个事件,

JButton jbtOK = new JButton("OK");ActionListener listener1 = new OKListenerClass();jbtOK.addActionListener(listener1);

点击该按钮时,JButton对象触发一个ActionEvent,然后将它作为参数传递以调用监听器的actionPerformed方法来处理这个事件
事件,事件监听器和监听器方法
这里写图片描述
这里写图片描述
现在我们可以编写一个程序,使用两个按钮控制一个圆的大小
这里写图片描述

**ControlCircle1.java代码:**package chapter16;import javax.swing.*;import java.awt.*;public class ControlCircle1 extends JFrame{    /**     *      */    private static final long serialVersionUID = 1L;    private JButton jbtEnlarge = new JButton("Enlarge");    private JButton jbtShrink = new JButton("Shrink");    private CirclePanel canvas = new CirclePanel();    public ControlCircle1()    {        JPanel panel = new JPanel();//Use the panel to group buttons        panel.add(jbtEnlarge);        panel.add(jbtShrink);        this.add(canvas,BorderLayout.CENTER);//Add canvas to center        this.add(panel, BorderLayout.SOUTH);//Add buttons to the frame    }    public static void main(String[] args)    {        JFrame frame = new ControlCircle1();        frame.setTitle("ControlCircle1");        frame.setLocationRelativeTo(null);        frame.setSize(200, 200);        frame.setVisible(true);    }}class CirclePanel extends JPanel{    /**     *      */    private static final long serialVersionUID = 1L;    private int radius = 5;//Default circle radius    /*Repaint重画 the circle*/    protected void paintComponent(Graphics g)    {        super.paintComponent(g);        g.drawOval(getWidth()/2-radius, getHeight()/2-radius, 2*radius, 2*radius);    }}

运行结果,但不能扩大缩小圆的大小:
这里写图片描述
如何使用按钮放大和缩小这个圆呢?当点击Enlarge按钮时,希望能用一个比较大的半径来重新绘制这个圆。该如何完成它呢?
1.定义一个名为EnlargeListener的监听器类,实现ActionListener.
2.创建一个监听器,并且将它注册到jdtEnlarge.
3.在CirclePanel中添加一个名为enlarge()的方法来增加半径,然后重新绘制面板.
4.实现EnlargeListener中的actionPerformed方法来调用canvas.enlarge().
5.为了让actionPerformed方法可以访问引用变量canvas,将EnlargeListener定义为ControlCircle2类的内部类.内部类定义在另一个类中
6.为了避免编译错误,CirclePanel类现在也定义为ControlCircle2的一个内部类.

package chapter16;import javax.swing.*;import java.awt.*;import java.awt.event.*;public class ControlCircle2 extends JFrame{    private static final long serialVersionUID = 1L;    private JButton jbtEnlarge = new JButton("Enlarge");    private JButton jbtShrink = new JButton("Shrink");    private CirclePanel canvas = new CirclePanel();    public ControlCircle2()    {        JPanel panel = new JPanel();        panel.add(jbtEnlarge);        panel.add(jbtShrink);        this.add(canvas,BorderLayout.CENTER);//Add canvas to center        this.add(panel, BorderLayout.SOUTH);//Add buttons to the frame        jbtEnlarge.addActionListener(new EnlargeListener());    }    public static void main(String[] args)    {        JFrame frame = new ControlCircle2();        frame.setTitle("ControlCircle2");        frame.setLocationRelativeTo(null);        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        frame.setSize(200, 200);        frame.setVisible(true);    }    class EnlargeListener implements ActionListener//Inner class    {        public void actionPerformed(ActionEvent e)        {            canvas.enlarge();        }    }    class CirclePanel extends JPanel//Inner class    {        private static final long serialVersionUID = 1L;        private int radius = 5;//Default circle radius        /*Enlarge the circle*/        public void enlarge()        {            radius++;            repaint();        }        /*Repaint the circle*/        protected void paintComponent(Graphics g)        {            super.paintComponent(g);            g.drawOval(getWidth()/2-radius, getHeight()/2-radius, 2*radius, 2*radius);        }    }}

这里写图片描述

内部类

内部类(inner class)或者潜套类(nested class)是定义在另一个类的范围的类.如下图a中的代码定义了两个独立的类:Test和A.图b的代码定义A为Test的一个内部类.
这里写图片描述
图c中定义在OuterClass中的InnerClass类是内部类的另一个例子.内部类可以像常规类一样使用.通常,如果内部类只是被外部类使用,那就将该类定义为内部类.一个内部类有如下特征:
1.一个内部类被编译成一个名为OuterClassName$InnerClassName.class的类.例如,在图b中Test中的内部类A被编译成Test$A.class
2.内部类可以引用定义在它嵌套的外部类中的数据和方法,所以,不需要将外部类对象的引用传递个内部类的构造方法.因为这个原因,内部类可以使程序更加简单和简洁.
3.使用可见性修饰符定义内部类时,遵从和应用与在类成员上一样的可见性规则.
4.可以将内部类定义为static,一个static内部类可以使用外部类的名字访问.一个static类是不能访问外部类的非静态成员的.
5.内部类的对象经常在外部类中创建.但是,也可以从另一个类中创建一个内部类的对象。如果该内部类是非静态的,就必须先创建一个外部类的实例,然后使用下面的语法创建一个内部类的对象:

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

如果内部类是静态的,那么使用下面的语法为它创建一个对象:

OuterClass.InnerClass innerObject = new OuterClass.InnerClass();
0 0
原创粉丝点击