前面的几篇笔记都写得太古板了,今天就换个新的写作风格来试试,暂且叫“案例导向式”吧,希望能对自己和别人的学习有所帮助。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
第一部分 问题场景描述
某日,小菜跑来问我:“phinecos,我真是快被java逼疯了,你可得帮帮我呀!!“
我转过头,“怎么了,小菜?“。
“是这样的,我现在在学习swing,每次用一个控件吧,如果想知道它能处理的事件的话,就得去查jdk文档,可sun那该死的文档总是把人搞得头晕,我只不过是想看看有什么事件可以处理而已,它那乱七八糟的文档反而把我快逼疯了,你给我出出主意吧。。。“小菜着急地摇着我的手说。
“哦,原来是这样啊,恩,可为什么你不用eclipse哪?它有提供你所需要的功能啊。”我不解的问。
“。。。这个,我不是不想用啊,可听人说,高手都是只用记事本和jdk的,我想成为高手,所以不敢用呀。”小菜支支唔晤的说。
“。。。。。。”
第二部分 分析与设计
需求是软件的关键。碰到上面小菜的问题了,我们就开始进行分析吧。小菜到底有什么需求哪?他是想查看一个swing控件类能够处理的事件列表,也就是它的所有addXXXListener方法。怎么办哪?看来只有两个解决方案了:一,劝小菜用eclipse,这样就可以直接利用eclipse的功能满足他的需求。(可这个已经被否定了,因为小菜要成为“高手”,^o^).二,那就只有为他开发一个小实用工具,让他可以查看各个Swing控件能够处理的事件,也就是把它的所有addXXXListener方法都列出来。
好了,东西比较小,那就先从GUI界面开始,至于核心的事件处理先不管,如下图:
用户界面代码如下:
importjava.awt.ActiveEvent;
importjava.awt.BorderLayout;
importjava.awt.Container;
importjava.awt.Event;
importjava.awt. event .ActionEvent;
importjava.awt. event .ActionListener;
importjavax.swing. * ;
importcom.vitamin.Console.console;
public class ShowAddListenersextendsJFrame
{
privateJLabellbName=null;
privateJTextFieldtfName=null;
privateJTextAreatResult=null;
privateJPanelpName=null;
publicShowAddListeners()
{
super();
this.initForm();
}
publicShowAddListeners(Stringtitle)
{
super(title);
this.initForm();
}
privatevoidinitForm()
{
this.lbName=newJLabel("请输入Swing控件的类名:");
this.tfName=newJTextField(20);
this.tResult=newJTextArea(40,50);
this.pName=newJPanel();
pName.add(this.lbName);
pName.add(this.tfName);
Containercon=this.getContentPane();
con.add(BorderLayout.NORTH,pName);
con.add(newJScrollPane(this.tResult));
tfListenertf1=newtfListener();
this.tfName.addActionListener(tf1);
console.run(this,600,600);
}
classtfListenerimplementsActionListener
{
publicvoidactionPerformed(ActionEvente)
{//核心处理代码处
if(tfName.getText().length()==0)
{
JOptionPane.showMessageDialog((JTextField)e.getSource(),"请输入控件类名称!!!","错误信息",JOptionPane.DEFAULT_OPTION);
return;
}
JOptionPane.showMessageDialog((JTextField)e.getSource(),"OK","信息",JOptionPane.DEFAULT_OPTION);
}
}
/**//**
*@paramargs
*/
publicstaticvoidmain(String[]args)
{
ShowAddListenerssl=newShowAddListeners("事件查看器");
}
}
在这里我对用户引发的键盘事件还只是简单地进行一个测试用的显示处理,还没有添加进用来完成所需功能的代码,但提早让用户体验到模型,哪怕是一个没有具体功能的虚模型也是一件好事情。
恩,问题来了,接收到用户输入的swing控件类名以后,该怎么去读取它所有的方法,并且能把adeeXXXListener()这样类型的方法给显示在TextArea控件里给用户哪?我第一反应是:要想获取一个类的所有方法,应该用RTTI,先用类名构造一个Class,再去尝试获取其方法。至于想从读出来的所有方法中只选出adeeXXXListener()类型的方法,应该要使用正则表达式来进行模式匹配吧。现有的思路是这样的,可对RTTI, 正则表达式,我都不熟悉,该怎么办哪?看来得靠jdk文档和google了。
好吧,打开jdk文档开始看Class的知识吧:
public static Class<?> forName(StringclassName)
throws ClassNotFoundException
返回与带有给定字符串名的类或接口相关联的 Class 对象。调用此方法等效于:
Class.forName(className, true, currentLoader)
其中 currentLoader 表示此类的定义类加载器。
例如,以下代码片段返回 java.lang.Thread 类的运行时 Class 描述符。
Class t = Class.forName("java.lang.Thread")
调用 forName("X") 将导致名为 X 的类被初始化。
恩,正是我要的,仿上面给的例子,我应该这样做:先获取用户输入的swing控件名称,如JButton,然后:]
Class t= Class.forName("java.swing."+name);
现在有了运行时的类了,接下来就是获取它的所有方法了
那我就应该这样:Method[] mt = t. getMethod();这样就把所有的方法读取到数组mt中了。
修改后的效果:
修改后的事件处理代码:
{
publicvoidactionPerformed(ActionEvente)
{
Stringname=tfName.getText().trim();
ClassclName=null;
if(name.length()==0)
{
JOptionPane.showMessageDialog((JTextField)e.getSource(),"请输入控件类名称!!!","错误信息",JOptionPane.DEFAULT_OPTION);
return;
}
else
{
try
{
clName=Class.forName("javax.swing."+name);
Method[]mt=clName.getMethods();
for(inti=0;i<mt.length;i++)
{
tResult.append(mt[i].toString()+"/n");
}
}
catch(ClassNotFoundExceptionex)
{
tResult.setText("没有找到匹配的方法名!!!");
}
}
}
}
现在已经初具雏形了,可获取的是全部方法,并不是我们原本想要的东西,还得从这个方法列表中进行一些筛选工作才行。
要选出只含有addXXXListener的方法,就应该尝试构造一个能够识别这样方法的正则表达式。翻阅jdk文档后,我写了这样一个正则表达式:
private static String StrReg = "add//w+?Listener";其中//w+?表示一个或多个字符
为了学习如何编写识别一个简单模式的程序,我写了一个简单的测试程序:
importjava.util.regex. * ;
public class regTest
{
publicstaticvoidmain(String[]args)
{
Patternp=null;
Matcherm=null;
p=Pattern.compile("a*b");
m=p.matcher("aaaaab");
if(m.matches()==true)
{
System.out.println("模式匹配成功");
}
else
{
System.out.println("匹配失败");
}
}
}
现在就来完成剩余的工作,代码如下:
importjava.awt.ActiveEvent;
importjava.awt.BorderLayout;
importjava.awt.Container;
importjava.awt.Event;
importjava.awt. event .ActionEvent;
importjava.awt. event .ActionListener;
importjava.lang.reflect.Method;
importjava.util.regex. * ;
importjavax.swing. * ;
importcom.vitamin.Console.console;
public class ShowAddListenersextendsJFrame
{
privateJLabellbName=null;
privateJTextFieldtfName=null;
privateJTextAreatResult=null;
privateJPanelpName=null;
privatestaticStringStrReg="add//w+?Listener";
privatestaticPatternpt=Pattern.compile(StrReg);
privatestaticMatchermc=null;
publicShowAddListeners()
{
super();
this.initForm();
}
publicShowAddListeners(Stringtitle)
{
super(title);
this.initForm();
}
privatevoidinitForm()
{
this.lbName=newJLabel("请输入Swing控件的类名:");
this.tfName=newJTextField(20);
this.tResult=newJTextArea(40,50);
this.pName=newJPanel();
pName.add(this.lbName);
pName.add(this.tfName);
Containercon=this.getContentPane();
con.add(BorderLayout.NORTH,pName);
con.add(newJScrollPane(this.tResult));
tfListenertf1=newtfListener();
this.tfName.addActionListener(tf1);
console.run(this,600,600);
}
classtfListenerimplementsActionListener
{
publicvoidactionPerformed(ActionEvente)
{
Stringname=tfName.getText().trim();
ClassclName=null;
if(name.length()==0)
{
JOptionPane.showMessageDialog((JTextField)e.getSource(),"请输入控件类名称!!!","错误信息",JOptionPane.DEFAULT_OPTION);
return;
}
else
{
try
{
clName=Class.forName("javax.swing."+name);
Method[]mt=clName.getMethods();
for(inti=0;i<mt.length;i++)
{
mc=pt.matcher(mt[i].toString());
if(mc.find())
{
tResult.append(mt[i].toString()+"/n");
}
}
}
catch(ClassNotFoundExceptionex)
{
tResult.setText("没有找到匹配的方法名!!!");
}
}
}
}
/**//**
*@paramargs
*/
publicstaticvoidmain(String[]args)
{
ShowAddListenerssl=newShowAddListeners("事件查看器");
}
}
结果如下,虽然还有很多地方不成熟,但也算是我的一个小作品吧,^o^