整个窗体程序的运行模式是:事件处理模式。需要理解这个模式,要了解3个基本概念
事件源:即产生这个事件的组件
监视器:即监视这个组件产生事件,即实现事件接口的类的对象
处理事件的接口:即这是一个类,实现了该种事件对应的接口,接口中必须实现一指定函数,当事件发生时,就会调用这个函数
进一步流程就是
1确定该组件的事件类型-2创建一个类实现该组件的事件类型对应的接口,这个类的对象就是监视器-3组件通过addXXXListen(监视器对象)将该
监视器添加-4在窗体上操作,产生对应的事件时将会执行那个监视器类中的对应函数【利用接口回调】。
需要注意的一点,并不是所有的组件都是同样事件类型,事件类型有很多种,有些组件是相同的,有些是不同的。
(一)ActionEvent事件
该事件的触发通常是 文本框,按钮,菜单项,密码框和单选按钮触发的。按钮和菜单项可以在点击时触发,文本框密码框之类的可以在回车时触发。
其要求的监视器类型接口是ActionListener,即需要有一个自定的类实现ActionListener接口,该接口的核心函数actionPerformed(ActionEvent e)需要实现该函数
组件对象通过addActionListener(ActionListener listener)将实现了ActionListener接口的类的对象传入。一但事件发生,就可以通过接口回调的方式调用这个actionPerformed函数。
需留意:这个ActionEvent类型的参数e,可以用他来获得到产生该事件时传来的数据,比如输入文本后回车,e可以获得文本的内容
通过e.getActionCommond()函数来获得(×稍后讲解他的局限性和另外的方法获得输入的内容)
以下是一个小案例,来展示从界面输入的值回车后,打印在控制台并输出他的长度
public class InputListener implements ActionListener {
/**
* 实现该接口的方法
* @param e
*/
public void actionPerformed(ActionEvent e)
{
//通过ActionEvent对象来获得输入
String str=e.getActionCommand();
System.out.println("输入了"+str+"长度为:"+str.length());
}
}
/**
* 一个简单的窗口
*/
public class SimpleForm extends JFrame {
private JTextField textField;//一个输入框
private InputListener inputListener;//一个实现了ActionListener接口的监视器
public SimpleForm()
{
//设置GUI
setLayout(new FlowLayout());
textField=new JTextField(10);
add(textField);
setBounds(100,100,310,260);
setVisible(true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
//设置监听器
inputListener=new InputListener();//监听器初始化
textField.addActionListener(inputListener);//为该组件添加监视器
}
}
//启动类
public class Main {
public static void main(String []args)
{
SimpleForm form=new SimpleForm();
}
}
刚刚提到过,可以ActionEvent获得输入,其实这种获取局限性很高,因为他只能获取一个输入,当有多个输入框,且使用一个按钮,按钮点击时获得所有输入框的值
这种方式就不适用了。以下提供下面一种解决方式
前提:需要保证这个实现接口的类能够拿到组件的引用,通过组件自己的get方法拿到组件中的值
改写如下
/**
* 一个简单的窗口
*/
public class SimpleForm extends JFrame {
private JTextField textField;//一个输入框
private InputListener inputListener;//一个实现了ActionListener接口的监视器
public SimpleForm()
{
//设置GUI
setLayout(new FlowLayout());
textField=new JTextField(10);
add(textField);
setBounds(100,100,310,260);
setVisible(true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
//设置监听器
inputListener=new InputListener();//监听器初始化
textField.addActionListener(inputListener);//为该组件添加监视器
inputListener.setJTextField(textField);//【法2】通过引用来拿到组件中的值
}
}
public class InputListener implements ActionListener {
//通过拿到组件引用获得里面的值的方法
private JTextField textField;
public void setJTextField(JTextField textField)
{
this.textField=textField;
}
/**
* 实现该接口的方法
* @param e
*/
public void actionPerformed(ActionEvent e)
{
//通过ActionEvent对象来获得输入
//String str=e.getActionCommand();
//System.out.println("输入了"+str+"长度为:"+str.length());
//【法2】不使用ActionEvent对象来获得组件的值,通过组件引用来拿到值
String str=textField.getText();
System.out.println("输入了"+str+"长度为:"+str.length());
}
}
效果如下-输入完后按回车

当然,这种效果并不直观,因为用户交互始终是在窗体上,且实际应用发布后不会有控制台,所以需要把结果也显示在窗体上。对以上程序进行了改进
public class InteractorListener implements ActionListener {
private JTextField textField;
private JTextArea textArea;
public void setJTextField(JTextField textField)
{
this.textField=textField;
}
public void setJTextArea(JTextArea textArea)
{
this.textArea=textArea;
}
/**
* 实现接口函数
*/
public void actionPerformed(ActionEvent e)
{
String input=textField.getText();//获取到文本框的输入
textArea.append("输入的是"+input+"长度为"+input.length()+"\n");//再将该输入作用到窗口中的组件
}
}
public class SimpleForm extends JFrame {
private JTextField inputTextField;
private JTextArea resultTextArea;
private JButton executeBtn;
private InteractorListener listener;
public SimpleForm()
{
//GUI部分
setLayout(new FlowLayout());
inputTextField=new JTextField(10);
resultTextArea=new JTextArea(9,30);
executeBtn=new JButton("执行");
add(new JScrollPane(resultTextArea));//将多行文本输入放入滚条面板,把滚条面板加入该面板
add(inputTextField);
add(executeBtn);
setVisible(true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setTitle("交互演示");
setBounds(100,100,460,360);
//设置监听器
listener=new InteractorListener();//实例化监听器
listener.setJTextField(inputTextField);//设置获取值组件
listener.setJTextArea(resultTextArea);//设置输出值的组件
inputTextField.addActionListener(listener);//为输入框事件源添加监听器:即代表回车后会触发事件
executeBtn.addActionListener(listener);//为按钮事件源添加监听器:即代表按钮点击后会触发事件
}
}
public class Main {
public static void main(String []args)
{
SimpleForm form=new SimpleForm();
}
}
效果如下

ActionEvent 变量的用处还是有的。当对于菜单项点击时使用,就是一大便利之处。
为多个菜单项添加同一个ActionEvent监听器对象,然后这个ActionEvent监听器的actionFormed函数中,通过e.getActionComond()来区分到底点击的是哪个菜单项,然后执行对应的操作。此时就是这种方式的优点,如果不这么做,通过获取组件引用的方式,就会产生多个(个数为菜单项的个数)监听器。更加麻烦
使用这种方式有一个前提,需要对JMenuItem 对象,即菜单项对象进行设置ActiionComond,即调用setActionComond(string str)后面有一个排序单词的窗体程序就展示了这个效果
(二)ItemEvent事件
该事件通常是由选择框(checkbox复选框,radioBox单选框)和下拉菜单触发的,选择框共有两种状态,即选中和未选中,当选中状态发生改变就会触发
ItemEvent事件,其要求的监视器接口类型为ItemListener,即需要有一个类来实现ItemListener接口,并实现其核心函数itemStateChanges(ItemEvent e).
组件通过addItemListener(ItemListener listener),传入实现了这个ItemListener接口的类的对象,一但事件发生,将会通过接口回调的方式调用这个addItemListener函数
以下用这个ItemEvent做了一个简易计算器
这个案例涉及到两个监听器
public class CaculateListener implements ActionListener {
private String fuhao;
public void setFuhao(String fuhao)
{
this.fuhao=fuhao;
}
private JTextField num1;
private JTextField num2;
private JButton caculateBtn;
private JTextArea resultArea;
public void setNum1(JTextField num1) {
this.num1 = num1;
}
public void setNum2(JTextField num2) {
this.num2 = num2;
}
public void setCaculateBtn(JButton caculateBtn) {
this.caculateBtn = caculateBtn;
}
public void setResultArea(JTextArea resultArea) {
this.resultArea = resultArea;
}
/**
* 实现该接口的函数
* @param actionEvent
*/
public void actionPerformed(ActionEvent actionEvent)
{
try {
double d1 = Double.parseDouble(num1.getText());
double d2=Double.parseDouble(num2.getText());
double res=0;
if(fuhao.equals("+"))
{
res=d1+d2;
}else if(fuhao.equals("-"))
{
res=d1-d2;
}else if(fuhao.equals("*"))
{
res=d1*d2;
}else if(fuhao.equals("/"))
{
res=d1/d2;
}
resultArea.append(d1+fuhao+d2+"结果为"+res+"\n");
}catch (Exception e)
{
System.out.println("发生运算错误,异常信息为:"+e);
}
}
}
public class FuhaoListener implements ItemListener {
private JComboBox fuhaoBox;//获得符号下拉菜单的引用,以便获取其中选到的值
public void setFuhaoBox(JComboBox fuhaoBox)
{
this.fuhaoBox=fuhaoBox;
}
private CaculateListener caculateListener;//获得另一个监听器的引用,因为需要吧选则的运算符传过去
public void setCaculateListener(CaculateListener listener)
{
this.caculateListener=listener;
}
/**
* 实现函数
* @param e
*/
public void itemStateChanged(ItemEvent e)
{
System.out.println("符号设置了");
String fuhao=fuhaoBox.getSelectedItem().toString();
//要把这个符号设置给另一个Listener,让他知道运算符是啥
caculateListener.setFuhao(fuhao);
}
}
public class CaculatorForm extends JFrame {
private JTextField inputNum1;//第一个操作数
private JTextField inputNum2;//第二个操作数
private JComboBox choiceFuhao;//操作符
private JButton caculateBtn;//进行计算
private JTextArea resTextArea;//结果显示区
//监视器定义
private CaculateListener caculateListener;
private FuhaoListener fuhaoListener;
public CaculatorForm()
{
//GUI部分
setLayout(new FlowLayout());
inputNum1=new JTextField(10);
inputNum2=new JTextField(10);
choiceFuhao=new JComboBox();
String []fuhaos={"+","-","*","/"};
for(String temp:fuhaos)
{
choiceFuhao.addItem(temp);
}
caculateBtn=new JButton("计算");
resTextArea=new JTextArea(9,30);
add(inputNum1);
add(inputNum2);
add(choiceFuhao);
add(caculateBtn);
add(resTextArea);
setVisible(true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setBounds(100,100,390,360);
setTitle("计算器");
//设置监听器
caculateListener=new CaculateListener();
fuhaoListener=new FuhaoListener();
//设置组件
fuhaoListener.setCaculateListener(caculateListener);//最重要的一步,因为该窗体涉及到两个监听器,且之间有通讯
caculateListener.setNum1(inputNum1);
caculateListener.setNum2(inputNum2);
caculateListener.setCaculateBtn(caculateBtn);
caculateListener.setResultArea(resTextArea);
fuhaoListener.setFuhaoBox(choiceFuhao);
//添加监听
choiceFuhao.addItemListener(fuhaoListener);
caculateBtn.addActionListener(caculateListener);
}
}
public class Main {
public static void main(String[] args)
{
CaculatorForm form=new CaculatorForm();
}
}
效果如下

(三)DocumentEvent事件
该事件的触发只有一个组件,即文本区组件JTextArea。只要当文本框中的内容发生改变时就会触发。其要求的监视器的接口类型为DocumentListener
即需要有一个类来实现DocumentListener接口,并实现该接口中的核心函数,该接口中有3个需要实现的函数:
1:void changedUpdate(DocumentEvent e)
2:void removeUpdate(DocumentEvent e)
3:void insertUpdate(DocumentEvent e)
由于文档变化一共就有以上3种可能,被替换,被移除,新插入。发生了对应的事件,就会执行其中对应的函数。
以下是一个demo,实时对左边输入的单词进行排序
public class EditorListener implements DocumentListener {
private JTextArea inputArea;
private JTextArea outputArea;
public void setInputArea(JTextArea inputArea) {
this.inputArea = inputArea;
}
public void setOutputArea(JTextArea outputArea) {
this.outputArea = outputArea;
}
//实现该接口的3个核心函数
//该案例的需求,只要变动了就进行排序,所以这3个函数执行的内容都是相同的,为了避免代码重复可以
public void insertUpdate(DocumentEvent e)
{
sort();
}
public void removeUpdate(DocumentEvent e)
{
sort();
}
public void changedUpdate(DocumentEvent e)
{
sort();
}
/**
* 排序单词函数
*/
private void sort()
{
String regex="[\\s\\d\\p{Punct}]+";
String inputStr=inputArea.getText();
String[] words=inputStr.split(regex);
Arrays.sort(words);
outputArea.setText(null);
for(String temp:words)
{
outputArea.append(temp+",");
}
}
}
public class MenuItemListener implements ActionListener {
private JTextArea inputArea,outputArea;
public void setInputArea(JTextArea inputArea)
{
this.inputArea=inputArea;
}
public void setOutputArea(JTextArea outputArea)
{
this.outputArea=outputArea;
}
public void actionPerformed(ActionEvent e)
{
//判断按下的是哪个菜单项,因为3个菜单项共有一个Listener
String actionCommand=e.getActionCommand();
if(actionCommand.equals("copy"))
{
outputArea.copy();
}else if(actionCommand.equals("cut"))
{
outputArea.cut();
}else if(actionCommand.equals("paste"))
{
inputArea.paste();
}
}
}
public class DocumentForm extends JFrame {
private JTextArea inputText,outputText;
private JMenuBar menuBar;
private JMenu menu;
private JMenuItem copy,cut,paste;
//监听器
private EditorListener editorListener;
private MenuItemListener menuItemListener;
public DocumentForm()
{
//GUI部分
setLayout(new FlowLayout());
inputText=new JTextArea(15,20);
outputText=new JTextArea(15,20);
outputText.setLineWrap(true);//设置文本区自动换行
outputText.setWrapStyleWord(true);//设置自动换行,以单词
menuBar=new JMenuBar();
menu=new JMenu("编辑");
copy=new JMenuItem("复制");
cut=new JMenuItem("剪切");
paste=new JMenuItem("粘贴");
copy.setActionCommand("copy");//设置代号-为使MenuItemListener能够判别具体的是哪个菜单项被点击
cut.setActionCommand("cut");//同上
paste.setActionCommand("paste");//同上
//将菜单项加入菜单中
menu.add(copy);
menu.add(cut);
menu.add(paste);
//菜单加入菜单条
menuBar.add(menu);
//界面加入这些组件,以滚动文本域的方式
add(new JScrollPane(inputText));
add(new JScrollPane(outputText));
setJMenuBar(menuBar);
setVisible(true);
setBounds(100,100,590,500);
setTitle("单词排序");
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
//设置监听器
editorListener=new EditorListener();
menuItemListener=new MenuItemListener();
editorListener.setInputArea(inputText);
editorListener.setOutputArea(outputText);
menuItemListener.setInputArea(inputText);
menuItemListener.setOutputArea(outputText);
//添加监听器
inputText.getDocument().addDocumentListener(editorListener);//DocumentListener
//菜单项中3个的Listener使用的是相同的
copy.addActionListener(menuItemListener);
cut.addActionListener(menuItemListener);
paste.addActionListener(menuItemListener);
}
}
public class Main {
public static void main(String []args)
{
DocumentForm form=new DocumentForm();
}
}
效果如下

上一篇:Java swing GUI 编程
https://blog.csdn.net/tanyu159/article/details/89047942
下一篇:Java swing开发窗体程序(三)事件(Mouse,Foucs,Key,Window)
https://blog.csdn.net/tanyu159/article/details/89113100
【!!!】欢迎关注我的个人线上课堂https://www.zuikakuedu.cn,内含JavaWeb与Unity游戏开发实战教程,完全免费!,Csdn博客涉及的课程资料也在该网站上
本文详细介绍了 Java Swing 中的事件处理机制,包括 ActionEvent、ItemEvent 和 DocumentEvent 三种事件类型及其应用场景。通过实例展示了如何实现事件监听及响应。

422

被折叠的 条评论
为什么被折叠?



