Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用动作在Java中创建菜单、工具栏和其他组件的正确方法_Java_User Interface_Swing - Fatal编程技术网

使用动作在Java中创建菜单、工具栏和其他组件的正确方法

使用动作在Java中创建菜单、工具栏和其他组件的正确方法,java,user-interface,swing,Java,User Interface,Swing,编写在Java Swing应用程序中构建菜单的简单方法是执行以下操作: JMenu fileMenu = new JMenu("File"); JMenuItem openItem = new JMenuItem("Open..."); openItem.addActionListener(new ActionListener() { /* action listener stuff */ } ) fileMenu.addMenuItem(openItem); 更有经验的开发人员会认识到,可以

编写在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);
我的问题是,管理这些动作对象的最佳方式是什么,以便它们可以跨菜单、工具栏等使用

  • 创建一个返回特定操作的工厂类
  • 在某个实用程序类中将所有操作声明为
    private static final Action
  • 利用Java应用程序框架
  • 还有别的吗

动作
是一个糟糕的抽象-一个焊接在穷人的
地图上的
动作监听器

当然,不要将它们分配给
静态
,因为它们是可变的,并且还需要一些上下文来有效地操作


我对GUI编程的一般建议是,它实际上与任何其他编程领域几乎相同。遵循通常的良好做法。值得注意的是,分层、关注点分离、很少使用(实现)继承,也不需要编写一大堆烂泥。

您可以使用专用的Map javax.swing.actionmap对所有抽象操作进行分组。 看

此外,每个JComponent都有一个内部actionMap(getActionMap())


希望这对你有所帮助,这与你的要求基本相同。编辑:我有一种感觉,人们不相信这是可能的或容易的,所以我做了--从零开始花了大约一个小时--如果我只使用一个方法作为目标,而不是将它反映到每个菜单项的单独方法中,那么我会花40分钟

这是我的建议。它是可行的,但它是一个大方法,而且丑陋——如果你使用它,就重构它。我可能会在接下来的几天里把它修好一点,我一直都想有一份这样的副本,以备再次使用

---原职

首先,记住将代码与数据分开。这意味着您不应键入:

new Menu("File...");
字符串“File…”是数据。如果你开始这样想,你会发现你的问题本身就有答案

首先,您需要建立一些数据。您需要将“文件…”和“保存”设置到菜单中。我通常从字符串数组开始(您可以轻松地将其移动到文件)

这是我开始使用的一种简单模式。然后你可以解析出+符号,并用它来表示“添加此符号时,在菜单中下拉一个级别”

这只是一个愚蠢的惯例,如果你不喜欢,就自己创造吧

下一步是将其绑定到要运行的代码。你可以让他们都调用同一个方法,但这真是个麻烦(巨大的开关语句)。一种可能是在读取数据时使用反射绑定方法名。这里有一个解决方案(同样,它可能不适合您的口味)

然后用大括号解析出这个东西,反射地将它连接到当前类中的一个方法,就完成了设置

在这一点上,我总是有一种诱惑,我学会了与之抗争,因为它永远不会奏效。诱惑是使用第一组数据(“文件…”),并对其进行操作以适应某种模式,并自动绑定到代码(在本例中,删除所有非alpha字符,将第一个字母小写并附加“Menu”以获得正确的方法名称)。您可以随意尝试,它非常吸引人,看起来也很圆滑,但当它不能满足某些需求时(例如在不同的子菜单中有两个名称完全相同的菜单项),您可以随时放弃它

另一种方法是,如果您的语言支持闭包,那么您实际上可以在同一个位置创建文件名和闭包

无论如何,一旦你开始像这样编码,你会发现你所有的菜单结构都是在一个10行的方法中,你可以改变它来满足你的需要。我曾经有过这样一个案例,我必须将一组菜单更改为按钮层次结构,我只用了2分钟就完成了

最后,您可以使用此模式轻松地设置动作对象,并更改它们的使用方式(在单个位置,一行代码中),因此您可以对它们进行实验。有很多方法可以使用它们,但是如果你不按照我在这里建议的那样做,你将不得不在每个菜单项上为每个更改重新实现,这真的很烦人——在一次更改之后,你将浪费比刚实现数据驱动解决方案更多的时间

这真的不是硬代码,应该需要一两个小时,然后你再也不用写新的菜单了(“…再次。相信我,这种工具总是值得的

编辑:

现在我几乎总是以数据驱动的方式编写代码。通常我会以正常的方式对一些东西进行原型化,识别模式并进行重构——如果重构正确,数据总是会被分解出来,剩下的东西是漂亮的、紧凑的和可维护的

我可以在不到1/2个小时内完成上面的建议(可能是一个小时来完成反射版本)。这几乎总是和使用非系数版本一样长,从那时起,每次更改都会使您的节省成倍增加

这与人们喜欢ruby的地方非常相似,除了ruby之外,他们似乎在代码中插入了更多的数据(这使得完全从代码中提取数据非常困难,这对于国际化来说总是一个很好的目标)

嗯,我有没有提到,如果你擅长像这样提取数据,i18n实际上是免费的

我建议你什么时候试一试,看看你是怎么想的。如果让你不舒服的话,把控件嵌入到字符串中是不必要的。我倾向于使用字符串/对象数组,因为它们很容易输入,在你创建时仍然在文件中
new Menu("File...");
new String[]{"File...","+Save","Load"...} 
new String[]{"File...[fileMenu]","+Save[saveMenu]","Load[loadMenu]"...}