2005年2月3日3:41:41
问题:
如果有两个JPopupMenu:a,b
a有个JMenu, b也有,但是b比a要多一个JMenuItem
我们用大写字母代表按钮上的名字
__D
按钮a: A__C__|__E
|__F
__D
C__|__E
| |__F
按钮b B--|
|--G
我最初这样写的:
JPopupMenu a = new JPopupMenu("A");
JPopupMenu b = new JPopupMenu("B");
JMenu c = new JPopupMenu(); //想让a和b公有c *_*
JMenuItem d = new JMenuItem("D");
JMenuItem e = new JMenuItem("E");
JMenuItem f = new JMenuItem("F");
c.add(d);
c.add(e);
c.add(f);
a.add(c);
现在的实际情况:a按钮是这样的
__D
A__C__|__E
|__F
好的,继续。
b.add(c); //这条语句是后面失败的原因
JMenuItem g = new JMenuItem("G");
b.add(g);
到现在我想象的情况是:
__D
A__C__|__E
|__F
__D
C__|__E
| |__F
B--|
|--G
但是一个组件是不能同时在两个Compoment里面的,所以
在b.add(c);这一句后,本来在a里面的c跑到b上面去了。
所以现在的实际情况是:
-
__D
C__|__E
| |__F
B--|
|--G
正如我们所见,按钮a什么都没了:(
那么怎么办呢??
在我脑海里首先得到的解决方法是安步就班的一个一个写,
a和b重复的部分就要写两遍。
举个例子,这样写:(当然我没有这样写,为重复的每个按钮变量生成啊,取名啊,设置字体啊,设置颜色啊。。。太累了)
JPopupMenu a = new JPopupMenu("A");
JPopupMenu b = new JPopupMenu("B");
JMenu c = new JPopupMenu();
JMenuItem d = new JMenuItem("D");
JMenuItem e = new JMenuItem("E");
JMenuItem f = new JMenuItem("F");
c.add(d);
c.add(e);
c.add(f);
a.add(c);//a结束
JMenu g = new JPopupMenu();
JMenuItem h = new JMenuItem("D");
JMenuItem i = new JMenuItem("E");
JMenuItem j = new JMenuItem("F");
g.add(h);
g.add(i);
g.add(j);
JMenuItem k = new JMenuItem("G");
b.add(g);
b.add(k);//b结束
好了,现在的实际结果一定是正确的。
看上去假设这么写的好象没多少代码量,但是如前面所说,我们这只是做演示,加上字体、颜色、监听器等等实际上的代码量是非常大的!
其实最大的问题还不是代码量的问题,问题是你的程序的可读性大大降低了!!
要知道swing程序员不仅要构建复杂而且友好的界面,还要对大量的各种事件写监听器,在一大堆难读的代码中寻找按钮还不如要人家去电影院看100遍《2046》:)(2046实在难看,我直说好了)
我们需要让我们的程序可读性高,我不记得是哪位高手说的了:在一份程序的生命周期里,10%的时间用来写它,90%的时间是拿来给人家看的。
诸多原因,我们务必用优雅的方式解决问题:)
我最开始是这样想的:
能否自己写一个MyPopupMenu extends JPopupMenu
如果MyPopupMenu p = new MyPopupMenu();
有一部分MenuItem是已经存在在p里了?
经过实践,实践是真理:)
很快就搞定了。方法是这样的:
制作我们自己的MyJPopupMenu类,它继承自JPopupMenu,把公有的部分全部写进去,这样无论要怎么增加JMenuItem都不会烦了.
MyJPopupButton类如下:
假设在主类ManagerUI.java里面
public class ManagerUI
{
private ...
private Font font = new Font(...);
private Color buttonColor = new Color(...);
...
public ManagerUI()
{
......
}
//这里是JPopupMenu的监听器
private class MyPopupMenuListener implements ActionListener
{
......
}
private class MyJPopupMenu extends JPopupMenu
{
private JMenuItem d = new JMenuItem("D");
private JMenuItem e = new JMenuItem("E");
private JMenuItem f = new JMenuItem("F");
public MyJPopupMenu()
{
}
public MyJPopupMenu(String name)
{
super(name);
}
//全部在这个方法里面一次性搞顶了,每个组件等会只需调用一下这个
//public方法就ok了
public void addPublicMenuItem()
{
//设置字体
d.setFont(font);
//设置颜色
d.setBackgroundColor(buttonColor);
e.setFont(font);
e.setBackgroundColor(buttonColor);
f.setFont(font);
f.setBackgroundColor(buttonColor);
MyPopopMenuListener mp = new MyPopopMenuListener();
d.addActionListener(mp);
e.addActionListener(mp);
f.addActionListener(mp);
c.add(d);
c.add(e);
c.add(f);
add(c); //注意add()方法是继承超类JPopupMenu的
}
}
}
在原来需要产生JPopupMenu的地方加上我们的对象,代码是这样的:
public class ManagerUI
{
private ...
private Font font = new Font(...);
private Color buttonColor = new Color(...);
private JPopupMenu a;//注意这里我们是用公共类,MyJPopupMenu的
private JPopupMenu b;//父类做的声明,等会需要向下转型
...
public ManagerUI()
{
......
a = new MyJPopupMenu("A"); //非常简洁
(MyJPopupMenu)a.addPublicMenuItem(); //记得向下转型
b = new MyJPopupMenu("B");
(MyJPopupMenu)b.addPublicMenuItem();
JMenuItem c = new JMenuItem("G");
b.add(c);
.....
}
//这里是JPopupMenu的监听器
private class MyPopupMenuListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
String id = ((JMenuItem)event.getSource()).getActionCommand();
if(id.equals("D"))
{...}
else if(id.equals("E"))
{...}
else if(id.equals("F"))
{...}
else if(id.equals("G"))
{...}
}
}
private class MyJPopupMenu
extends JPopupMenu
implement ActionListener
{
private JMenuItem d = new JMenuItem("D");
private JMenuItem e = new JMenuItem("E");
private JMenuItem f = new JMenuItem("F");
public MyJPopupMenu()
{
}
public MyJPopupMenu(String name)
{
super(name);
}
public void addPublicMenu()
{
d.setFont(font);
d.setBackgroundColor(buttonColor);
e.setFont(font);
e.setBackgroundColor(buttonColor);
f.setFont(font);
f.setBackgroundColor(buttonColor);
MyPopopMenuListener mp = new MyPopopMenuListener();
d.addActionListener(mp);
e.addActionListener(mp);
f.addActionListener(mp);
c.add(d);
c.add(e);
c.add(f);
add(c);
}
}
}
最后运行的情况不用我说了,绝对正确无误:)
完了吗?
记得James Cooper说过反正他认为类越多就越难管理,我们可以进一步进行优化,
把JPopupMenu按钮的监听器类删掉吧,为什么不呢?
很简单,只需要用MyJPopupMenu类实现ActionListener接口就可以了
这样完整代码变成这样:
public class ManagerUI
{
private ...
private Font font = new Font(...);
private Color buttonColor = new Color(...);
private JPopupMenu a;
private JPopupMenu b;
...
public ManagerUI()
{
......
a = new MyJPopupMenu("A");
(MyJPopupMenu)a.addPublicMenuItem();
b = new MyJPopupMenu("B");
(MyJPopupMenu)b.addPublicMenuItem();
JMenuItem c = new JMenuItem("G");
b.add(c);
.....
}
private class MyJPopupMenu
extends JPopupMenu
implement ActionListener
{
private JMenuItem d = new JMenuItem("D");
private JMenuItem e = new JMenuItem("E");
private JMenuItem f = new JMenuItem("F");
public MyJPopupMenu()
{
}
public MyJPopupMenu(String name)
{
super(name);
}
public void addPublicMenu()
{
d.setFont(font);
d.setBackgroundColor(buttonColor);
e.setFont(font);
e.setBackgroundColor(buttonColor);
f.setFont(font);
f.setBackgroundColor(buttonColor);
MyPopopMenuListener mp = new MyPopopMenuListener();
d.addActionListener(this); //注意:记得把这里改成this
e.addActionListener(this);
f.addActionListener(this);
c.add(d);
c.add(e);
c.add(f);
add(c);
}
//把actionPerformed()方法写到这里
public void actionPerformed(ActionEvent event)
{
String id = ((JMenuItem)event.getSource()).getActionCommand();
if(id.equals("D"))
{...}
else if(id.equals("E"))
{...}
else if(id.equals("F"))
{...}
else if(id.equals("G"))
{...}
}
}
}
终于搞定了,以上代码为了方便阅读用a,b,c...等字母表示的,实际情况当然不是这样:)
小结:
没有什么技术含量...:)
我是菜鸟,平时注意自我总结小经验对自己的Java水平一定有帮助的:)
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/starshus/archive/2005/03/01/306450.aspx