一、事件和事件源
事件:事件可以定义为程序发生了某些事情的信号
源对象(源组件):能创建一个事件并触发该事件的组件成为源对象
事件类的根类:java.util.EventObject
可以使用EventObject类中的实例方法getSource()获得事件的源对象
如果一个组件可以触发某个事件,那么这个事件的任意子类都可以触发同类型的事件,如因为GUI组件的父类Component可以触发MouseEvent、KeyEvent、FocusEvent和ComponentEvent,所以任意的GUI组件都可以触发上述事件
二、监听器、注册以及处理事件
java使用一种基于委托的模型来处理事件:源对象触发一个事件,对此事件感兴趣的对象会处理它。将对此事件感兴趣的对象称为监听器。
一个对象要称为源对象上的事件监听器,需要具备两个条件:
(1)监听器对象的类必须是相应的事件监听器接口的实例,以确保监听器有处理这个事件的正确方法。
(2)监听器对象必须由源对象注册。注册方法依赖于事件的类型。
下面我们编写一个程序,使用两个按钮控制一个圆的大小
ControlCircle1.java
import javax.swing.*;
import java.awt.*;
public class ControlCircle1 extends JFrame{
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);//将画布添加到中央
this.add(panel,BorderLayout.SOUTH);//将装有两个按钮的面板添加到SOUTH的位置
}
public static void main(String[] args){
JFrame frame = new ControlCircle1();
frame.setTitle("ControlCircle1");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200,200);
frame.setVisible(true);
}
}
class CirclePanel extends JPanel{
private int radius = 5;//默认的圆的半径
/**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和ShrinkListener的监听器类,实现ActionListener
(2)创建两个监听器,并且将它注册到jbtEnlarge和jbtShrink
(3)在CirclePanel中添加一个名为enlarge()的方法来增加半径,添加一个名为shrink()的方法来缩小半径,然后重新绘制面板
(4)实现EnlargeListener中的actionPerformed方法来调用canvas.enlarge()和canvas.shrink()
(5)为了让actionPerformed方法可以访问引用变量canvas,将EnlargeListener定义为ControlCircle2类的内部类。内部类定义在另一个类中。
(6)为了避免编译错误,CirclePanel类现在也定义为ControlCircle2的一个内部类
以下代码实现了通过Enlarge按钮放大圆,通过Shrink按钮缩小圆
ControlCircle2.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ControlCircle2 extends JFrame{
private JButton jbtEnlarge = new JButton("Enlarge");
private JButton jbtShrink = new JButton("Shrink");
private CirclePanel canvas = new CirclePanel();
public ControlCircle2(){
JPanel panel = new JPanel();//use the panel to group buttons
panel.add(jbtEnlarge);
panel.add(jbtShrink);
this.add(canvas,BorderLayout.CENTER);
this.add(panel,BorderLayout.SOUTH);
jbtEnlarge.addActionListener(new EnlargeListener());
jbtShrink.addActionListener(new ShrinkListener());
}
/**Main Method**/
public static void main(String[] args){
JFrame frame = new ControlCircle2();
frame.setTitle("ControlCircle2");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,400);
frame.setVisible(true);
}
//定义一个名为EnlargeListener的监听器类,实现ActionListener
class EnlargeListener implements ActionListener{
public void actionPerformed(ActionEvent e){
canvas.enlarge();
}
}
//定义一个名为ShrinkListener的监听器类,实现ActionListener
class ShrinkListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
canvas.shrink();
}
}
class CirclePanel extends JPanel{
private int radius = 5;//默认圆的半径为5
/**Enlarge the circle */
public void enlarge(){
radius++;
repaint();
}
public void shrink() {
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);
}
}
}
三、内部类
内部类或者嵌套类是定义在另一个类的范围内的类
两个独立的类:
public class Test{
...
}
public class A{
...
}
public class Test{
...
//inner class
public class A{
...
}
}
内部类可以像常规类一样使用。如果内部类只是被外部类使用,那就将该类定义为内部类。
一个内部类有如下的特征:
(1)一个内部类被编译成一个名为OuterClassNameInnerlClassName.class的类。例如:Test中的A被编译为TestInnerlClassName.class的类。例如:Test中的A被编译为TestA.class。
(2)内部类可以引用定义在它嵌套的外部类中的数据和方法,所以,不需要将外部类对象的引用传递给内部类的构造方法。因此,内部类可以使程序更加简单和简洁
(3)使用可见性修饰符定义内部类时,遵从和应用与在类成员上一样的可见性规则,
(4)可以将内部类定义为static。一个static内部类可以使用外部类的名字访问。一个static类是不能访问外部类的非静态成员的。
(5)内部类的对象经常在外部类中创建。但是,也可以从另一个类中创建一个内部类的对象。如果该内部类是非静态的,那就必须先创建一个外部类的实例,然后使用下面的语法创建一个内部类的对象:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
如果内部类是静态的,那么使用下面的语法为它创建一个对象:
OuterClass.InnerClass innerObject = new OuterClass.InnerClass();
内部类的一个简单应用就是将从属类合并到主类中。这可以减少源文件的数量。例如,将类A合并到类Test中,只创建一个源文件Test.java,最终的类文件是Test.class和Test$A.class
内部类的另一个实际应用是为了避免类命名冲突