代码之家  ›  专栏  ›  技术社区  ›  David Koelle

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

  •  8
  • David Koelle  · 技术社区  · 17 年前

    编写在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 在一些实用类?
    6 回复  |  直到 17 年前
        1
  •  4
  •   ShawnD    17 年前

    Swing Application Framework

    此框架将允许您拥有一个资源文件,您可以在其中定义所有菜单文本、工具提示和图标。我认为图标是关键,你不必自己加载它们。此外,如果您有任何需要启用/禁用的操作,则可以重写该方法以控制其状态。

    这个网站值得一读。

        2
  •  1
  •   Pierre    17 年前

    看见 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));
     }
    
    }
    

    希望能有帮助

        3
  •  0
  •   Tom Hawtin - tackline    17 年前

    Action 是一个糟糕的抽象-一个 ActionListener 焊接在一个穷人的脖子上 Map .

    static 因为它们是可变的,也需要一些上下文来有效地操作。

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

        4
  •  0
  •   Community Mohan Dere    9 年前

    this question ,这和你问的差不多。

        5
  •  0
  •   davetron5000    17 年前
    1. 为应用程序创建基本操作;这对你以后会有很大帮助
    2. 要像在代码中一样创建动作,而要支持基本动作的子类

    要组织它们,这将取决于您对它们所做的操作,您可能会以一种方式组织一些操作,而其他操作则以另一种方式创建。一切都要看情况而定。

    根据用户界面的不同,您可能需要区分“静态”操作(即应用程序中始终可用的内容,如菜单系统)和仅在特定屏幕或特定位置创建的动态操作。

    在任何情况下,使用专门的基本操作的具体子类将帮助您保持这些事情的有序性。你呢

        6
  •  0
  •   Bill K    17 年前

    编辑:我感觉人们不相信这是可能的或容易的,所以我做了——从零开始花了大约一个小时——如果我只使用一个方法作为目标,而不是将它反映到每个菜单项的单独方法中,可能需要40分钟。

    Tested source code

    ---原职

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

    new Menu("File...");
    

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

    new String[]{"File...","+Save","Load"...} 
    

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

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

    new String[]{"File...[fileMenu]","+Save[saveMenu]","Load[loadMenu]"...} 
    

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

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

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

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

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

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

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

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

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

    我建议你找个时间试试,看看你的想法。如果控件使您感到不舒服,那么在字符串中嵌入控件是不必要的。我倾向于使用字符串/对象数组,只是因为它们很容易输入,在编码时仍然在文件中,以后外部化也很简单,但是如果您喜欢YML、XML或属性文件,请使用您喜欢的任何东西--只需从代码中提取数据!