在Java Swing应用程序中编写菜单的简单方法是执行以下操作:
JMenu fileMenu = new JMenu("File");
JMenuItem openItem = new JMenuItem("Open...");
openItem.addActionListener(new ActionListener() { /* action listener stuff */ } )
fileMenu.addMenuItem(openItem);
经验丰富的开发人员将认识到可以通过各种机制访问操作 - 菜单,工具栏按钮,甚至系统中的其他工作流程。那个人更有可能写:
Action openAction = new AbstractAction();
openAction.setName("Open...");
openAction.addActionListener(new ActionListener() { /* action listener stuff */ } )
...
JMenuItem openItem = new JMenuItem(openAction);
我的问题是,管理这些Action对象的最佳方法是什么,以便可以跨菜单,工具栏等使用它们?
private static final Action
? 答案 0 :(得分:4)
我开发的需要在菜单,工具栏和其他按钮上使用相同操作的应用程序已经使用Swing Application Framework完成。
此框架允许您拥有一个资源文件,您可以在其中定义所有菜单文本,工具提示和图标。我认为图标是关键,你不必自己加载它们。此外,如果您需要启用/禁用任何操作,则可以覆盖该方法以控制其状态。
该网站值得一读。
答案 1 :(得分:1)
您可以使用专用的Map javax.swing.actionmap对所有abstractAction进行分组。 见http://java.sun.com/javase/6/docs/api/javax/swing/ActionMap.html
此外,每个JComponent都有一个内部actionMap(getActionMap())。
class MyComponent
extends JPanel
{
public static final String ACTION_NAME1="my.action.1";
public MyComponent()
{
AbstractAction action= new AbstractAction() { ... }
getActionMap().put(ACTION_NAME1,action);
...
menu.add(getActionMap().get(ACTION_NAME1));
}
}
希望有所帮助
答案 2 :(得分:0)
Action
是一个糟糕的抽象 - ActionListener
焊接到穷人的Map
。
当然不要将它们分配给static
,因为它们是可变的,并且还需要一些上下文来有效地运行。
我对GUI编程的一般建议是要注意它实际上与任何其他编程领域大致相同。遵循通常的良好做法。值得注意的是,分层,关注点分离,很少使用(实现)继承,并且不会写出大量的泥浆。
答案 3 :(得分:0)
另请参阅this question,这与您提出的内容几乎相同。
答案 4 :(得分:0)
这是Tested source code。它是有效的,但是它是一个很大的方法而且难看 - 如果你使用它就重构它。我可能会在接下来的几天内修复它,我一直希望有一个这样的副本可以继续使用。
---原帖
首先,请记住将代码与数据分开。这意味着你永远不应该输入:
new Menu("File...");
字符串“File ...”是数据。如果你开始这样思考,你会发现你的问题会自行解决。
首先,您需要建立一些数据。您需要将“文件...”和“保存”放入菜单中。我通常从一个字符串数组开始(你可以很容易地移动到一个文件)
new String[]{"File...","+Save","Load"...}
这是我开始使用的简单模式之一。然后你可以解析+符号并用它来表示“当你添加这个时在菜单中下拉一个级别”
这只是一个愚蠢的约定,如果你不喜欢它就发明你自己的。
下一步是将其绑定到要运行的代码。你可以让他们都调用相同的方法,但屁股的痛苦(巨人开关声明)。一种可能性是在读取数据时使用反射来绑定方法名称。这是一个解决方案(同样可能不符合您的口味)
new String[]{"File...[fileMenu]","+Save[saveMenu]","Load[loadMenu]"...}
然后你用方括号解析出来的东西,反过来把它挂钩到你当前班级的一个方法中然后就可以了。
此时我总是有一种诱惑,我已经学会了打击它,因为它永远不会解决。诱惑是使用第一组数据(“文件...”)并操纵它以适应某些模式并自动绑定到您的代码(在这种情况下,删除所有非alpha字符,使第一个字母小写和附加“菜单”以获取正确的方法名称)。随意尝试这个,它非常有吸引力,看起来很光滑,但是当它不满足某些需要时(例如在不同的子菜单中具有完全相同名称的两个菜单项),请准备放弃它。
另一种方法是,如果您的语言支持闭包,那么您实际上可以在同一个地方创建文件名和闭包。
无论如何,一旦你开始这样的编码,你会发现你所有的菜单结构都采用单一的10行方法,你可以改变它以满足你的需要。我有一个案例,我必须将一组菜单更改为按钮层次结构,我在2分钟内完成。
最后,您可以使用此模式轻松设置操作对象并轻松更改它们的使用方式(在单个位置,单行代码中),以便您进行实验。有很多种方法可以使用它们,但是如果你不按照我在这里推荐的方式进行操作,你将最终不得不在每个菜单项中重新实现每次更改,这真的很烦人 - 在一次更改后你与您刚刚实施数据驱动的解决方案相比,浪费的时间会更多。
这真的不是硬代码,应该花一两个小时然后你再也不用写新菜单了(“......再说一遍。相信我,这种工具总是值得的。
编辑:
我这些天总是编码数据驱动。通常我会以正常的方式对一些东西进行原型设计,识别模式和重构 - 如果你正确地进行重构,那么数据总是会有所影响,而你剩下的就是美观,紧凑和可维护。
我可以在不到1/2小时内完成我上面提到的建议(可能需要一个小时来完成反射版本)。这几乎总是与使用未经过制作的版本一样长,从那时起,每次更改都会节省您的成本。
这与人们喜欢ruby非常相似,除了ruby之外,他们似乎在代码中插入了更多的数据(这使得从代码中完全提取数据非常困难,这对于国际化来说总是一个很好的目标)。
嗯,我是否提到如果你擅长提取这样的数据,i18n几乎是免费的?我建议你稍微尝试一下,看看你的想法。如果让您感到不舒服,则无需将控件嵌入字符串中。我倾向于使用字符串/对象数组,因为它们很容易输入,在编码时仍然在文件中,以后稍微外化,但如果您喜欢YML或XML或属性文件,请使用您感觉舒服的任何内容用 - 只需从代码中抽象出数据!
答案 5 :(得分:0)
要组织它们,它将取决于您对它们的处理方式,并且您可能采用一种方式组织某些操作,而其他方式则采用不同的方式。这一切都取决于。
您想要的是在代码中找到/创建操作的一致方法。
根据您的用户界面,您可能需要区分“静态”操作(即应用程序中始终可用的内容,例如菜单系统)和仅在特定屏幕或某些位置创建的动态操作。 / p>
在任何情况下,使用专门的基本操作的具体子类将帮助您保持这些内容的有序性。您不想要的是在代码中指定标签,助记符和图标等内容。