Java的GUI事件处理

事件和监听器

先来了解什么是事件,事件就是表示一个对象的状态发生了变化。例如,每当一个按钮按下时,实际按钮的状态就发生了改变,那么此时就会产生一个事件,而如果需要事件的监听者不断的监听事件的变化,并根据这些事件进行相应的处理。

Swing 编程中,依然使用了最早的 AWT 的事件处理方式,所有的事件类(基本上任意一个组件都有对应的事件)都是 EventObject 类的子类。如下图所示。
Java的GUI事件处理_第1张图片
EventObject 类的JDK源码:

public class EventObject implements java.io.Serializable {
    private static final long serialVersionUID = 5516075349620653480L;
    protected transient Object  source;
    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");

        this.source = source;
    }
    public Object getSource() {
        return source;
    }
    public String toString() {
        return getClass().getName() + "[source=" + source + "]";
    }
}

EventObject 中定义了三个方法,其中可以通过 getSource() 方法取得发生此事件的源对象。

事件监听器

如果没有能够接受和处理事件的对象,图形界面程序生成的一切事件都是无用的,这些事件接收对象被称为事件监听器。

所有的事件监听器都是以接口的形式出现的,处理是只需要实现此接口即可。

整个事件处理的流程如下图所示:
Java的GUI事件处理_第2张图片

窗体事件

WindowListener 是专门处理窗体的事件监听接口,一个窗体的所有变换,如窗口打开,关闭等都可以使用 WindowListener 这个接口进行监听。WindowListener 接口定义的方法如下表所示。

序号 方法 描述
1 void windowActivated(WindowEvent e) 将窗口变为活动窗口时触发
2 void windowDeactivated(WindowEvent e) 将窗体变为不活动窗口是触发
3 void windowClosing(WindowEvent e) 当窗口正在关闭时触发
4 void windowClosed(WindowEvent e) 当窗口被关闭了触发
5 void windowIconified(WindowEvent e) 窗口从正常状态变为最小化状态时触发
6 void windowDeiconified(WindowEvent e) 窗口从最小化状态变为正常状态时触发
7 void windowOpened(WindowEvent e) 窗口打开是触发

通过实现 WindowListener 接口来监听窗体事件

import java.awt.event.WindowListener;
import java.awt.event.WindowEvent;
import java.awt.Color;
import javax.swing.JFrame;
//通过实现事件监听器接口方式来监听事件
class MyWindowEventHandle implements WindowListener
{
	public void windowActivated(WindowEvent e)
	{
		System.out.println("windowActivated --> 窗口被选中");
	}
	public void windowClosed(WindowEvent e)
	{
		System.out.println("windowClosed --> 窗口被关闭");
	}
	public void windowClosing(WindowEvent e)
	{
		System.out.println("windowClosing --> 窗口关闭");
		System.exit(1);//退出程序
	}
	public void windowDeactivated(WindowEvent e)
	{
		System.out.println("windowDeactivated --> 取消窗口选中");
	}
	public void windowDeiconified(WindowEvent e)
	{
		System.out.println("windowDeiconified --> 窗口从最小化恢复");
	}
	public void windowIconified(WindowEvent e)
	{
		System.out.println("windowIconified --> 窗口最小化");
	}
	public void windowOpened(WindowEvent e)
	{
		System.out.println("windowOpened --> 窗口被打开");
	}
}

public class MyEventWindowEventJFrame01
{
	public static void main(String args[])
	{
		JFrame frame = new JFrame("窗体事件处理");
		//窗体中加入事件监听器
		frame.addWindowListener(new MyWindowEventHandle()); // 加入事件
		frame.setSize(300, 150);
		//设置背景颜色
		frame.getContentPane().setBackground(Color.PINK);
		frame.setLocation(300, 200);
		frame.setVisible(true);
	}
}

当鼠标移动当窗体上的时候,窗体被选中,当鼠标移出窗体之外的位置时,窗体不被选中。当最小化窗体的时候,触发最小化事件,再次显示点击窗体按钮时,触发从最小化恢复事件,最大化好像没有对应的事件。在上面的窗口关闭事件中写入了 System.exit(1) 语句,这样当关闭窗体时程序结束。关闭按钮起作用。

监听适配器

如果现在只需要对关闭窗体的事件进行监听,其他操作我们根本不关心,就没必要通过实现接口的方式来监听事件,因为通过实现接口的方式,我们要实现事件监听接口( WindowListener )里面的所有的方法。
为解决上述问题,引入适配器设计模式,在实现类和接口之间增加一个过渡的抽象来,字节继承抽象类就可以根据自己的需要进行事件方法的覆盖。在整个事件处理中提供了很多的 Adapter (适配器)类,方便用户进行事件处理的实现。以 WindowAdapter 为例,用户只需要继承 WindowAdapter 类,就可以根据自己的需要覆盖方法,如果现在只关心窗体的关闭事件方法,则只下子类中覆盖 windowClosing() 方法即可。

实例:通过 WindowAdapter 实现监听

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.Color;
import javax.swing.JFrame;

class MyWindowEventHandle1 extends WindowAdapter
{
	public void windowClosing(WindowEvent e)
	{
		System.out.println("windowClosing --> 窗口关闭");
		System.exit(1);
	}
}

public class MyEventWindowEventJFrame02
{
	public static void main(String args[])
	{
		JFrame frame = new JFrame("通过适配器监听处理事件");
		frame.addWindowListener(new MyWindowEventHandle1()); // 加入事件
		frame.setSize(300, 150);
		frame.getContentPane().setBackground(Color.yellow);
		frame.setLocation(300, 200);
		frame.setVisible(true);
	}
}

关闭该窗体,控制台输出:

 windowClosing --> 窗口关闭

匿名内部类

如果此监听处理只需要操作一次,没有必要将其设置成为一单独的类,此时可以利用匿名内部类来事件的操作。

实例:使用匿名内部类方式实现事件监听

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.Color;
import javax.swing.JFrame;
public class MyEventWindowEventJFrame03
{
	public static void main(String args[])
	{
		JFrame frame = new JFrame("使用匿名内部来");
		// 加入事件
		frame.addWindowListener(
		//匿名内部类方式,实现事件监听。
		new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				System.out.println("windowClosing --> 窗口关闭");
				System.exit(1);
			}
		}); 
		frame.setSize(300, 150);
		frame.getContentPane().setBackground(Color.green);
		frame.setLocation(300, 200);
		frame.setVisible(true);
	}
}

点击窗体的关闭按钮,控制输出:

 windowClosing --> 窗口关闭

使用适配器操作类,直接编写匿名内部类就可以减少监听类的定义,这是在开发中比较常见的一种方法。

动作事件及监听处理

要想让一个按钮变得有意义,就必须使用事件处理。在 Swing 的事件处理中,可以使用 ActionListener 接口处理按钮的动作事件。 ActionListener 接口只定义了一个方法,如下表所示。

序号 事件 描述
1 void actionPerformed(ActionEvent e) 发生操作时调用

下面使用上面的监听接口监听按钮的单击事件。

实例:使用 ActionListener 监听
下面实现一个简单的用户登录操作:如果用户输入的用户名为 user ,密码为 admin,则认为是合法用户,提示登录成功的信息,反之,则提示登录失败的信息,代码如下所示。

import java.awt.event.WindowAdapter;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.ActionEvent;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JPasswordField;
import javax.swing.JPanel;

class LoginCheck
{
	private String name;
	private String password;
	public LoginCheck(String name, String password)
	{
		this.name = name;
		this.password = password;
	}

	public boolean ispass()
	{
		if ("user".equals(name) && "admin".equals(password))
		{
			return true;
		} else
		{
			return false;
		}
	}
};

class ActionHandle1
{
	private JFrame frame = new JFrame("简单登录模式");
	private JButton submit = new JButton("登陆");
	private JButton reset = new JButton("重置");
	private JLabel nameLab = new JLabel("用户名:");
	private JLabel passLab = new JLabel("密   码:");
	private JLabel infoLab = new JLabel("请输入用户名和密码");
	private JTextField nameText = new JTextField(10);
	private JPasswordField passText = new JPasswordField();
	private JPanel pan = new JPanel();
	public ActionHandle1()
	{
		// 设置字体
		Font fnt = new Font("Serief", Font.ITALIC + Font.BOLD, 14);
		// 标签设置字体样式
		infoLab.setFont(fnt); // 设置标签的显示文字
		submit.setFont(fnt); 
		reset.setFont(fnt); 
		nameLab.setFont(fnt); 
		passLab.setFont(fnt); 
		// 监听登录按钮事件
		submit.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				if (e.getSource() == submit)
				{
					// 获取名字框的文本
					String tname = nameText.getText();
					// 获取密码框的文本
					String tpass = new String(passText.getPassword());
					// 检查用户名和密码
					LoginCheck log = new LoginCheck(tname, tpass);
					if (log.ispass())
					{
						// 设置提示标签
						infoLab.setText("登陆成功,欢迎光临!");
					} else
					{
						infoLab.setText("登陆失败,错误的用户名或密码!");
					}
				}
			}
		});
		// 设置重置按钮事件处理
		reset.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				if (e.getSource() == reset)
				{
					// 用户名和密码框置空
					nameText.setText("");
					passText.setText("");
					infoLab.setText("请输入用户名和密码");
				}
			}
		});
		// 关闭窗口事件
		frame.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				System.exit(1);
			}
		}); // 加入事件
		// 不适用布局管理器
		frame.setLayout(null);
		// 设置第一行的三个组件的位置和大小
		nameLab.setBounds(  5, 5, 60, 20);
		nameText.setBounds(65, 5, 100, 20);
		submit.setBounds( 170, 5, 80, 20);
		// 设置第2行的三个组件的位置和大小
		passLab.setBounds(  5, 30, 60, 20);
		passText.setBounds(65, 30, 100, 20);
		reset.setBounds(  170, 30, 80, 20);
		// 设置提示标签的位置和大小
		infoLab.setBounds(5, 65, 220, 30);
		// 添加组件
		// 添加第一行
		frame.add(nameLab);
		frame.add(nameText);
		frame.add(submit);
		// 添加第二行
		frame.add(passLab);
		frame.add(passText);
		frame.add(reset);
		// 添加第三行
		frame.add(infoLab);
		frame.setSize(280, 130);
		// 设置窗体背景颜色
		frame.getContentPane().setBackground(Color.PINK);
		frame.setLocation(300, 200);
		frame.setVisible(true);

	}
}

public class MyActionEventDemo03
{
	public static void main(String args[])
	{
		new ActionHandle1();
	}
}

你可能感兴趣的:(Java程序设计)