【问题标题】:How do I build a JMenu dynamically (and not merely run-time creation)?如何动态构建 JMenu(而不仅仅是运行时创建)?
【发布时间】:2018-12-22 08:52:06
【问题描述】:

需要明确的是,这里的几个看起来相似的条目实际上并没有讨论动态构建菜单,因为它们的所有对象名称选择等都已经在它们的代码中,因为它们已经在源代码中编写了固定字符串;他们所做的只是等到运行时创建他们静态设计的菜单项。以下是我发现的两个类似条目:OneTwo. 那里的问题仅与刷新显示的琐碎(但至关重要)任务有关,与实际动态创建内容无关。

与此形成鲜明对比的是,我想做的是真正动态地添加:我希望用户能够选择将项目添加到子菜单中,然后他们可以在以后选择并在应用程序中采取行动。

让我们以简单地向菜单添加一个整数值,然后稍后可以选择它的情况为例,类似于使用组合框可以轻松完成但使用菜单完成的操作。

问题不在于与定义有关的语法,例如,MenuListener 将指向一个知道如何操作的方法,这不是问题。相反,我只是不太了解动态命名空间,以及如何“取消引用”字符串,例如,作为对象名称。坦率地说,我如何动态命名我没有预料到创建的新对象(不是实物,而是数量)? IOW,我如何获取一个实际上包含我想要运行的代码的巧妙构造的字符串,然后让 Java 运行它? Java 语法是什么?也许问题可以简化为对象名称;比如说,名称是我可以构造的字符串;如何在我的JMenuItem 声明中使用它? ...我知道如何在 BASH 中执行此操作,但是如何在 Java 中执行此操作?

(我希望我不必将它创建为文件,编译它,然后以某种方式将类文件附加到我正在运行的程序中,然后运行它——该死,这太麻烦了!)

谢谢。

【问题讨论】:

  • 我想看一个这样的伪例子。您已经知道“种类”但不知道数字,但这与接受包含 Java 的字符串有什么关系?代码?
  • 动态创建菜单与创建静态菜单没有什么不同,只是属性变成了变量而不是硬编码。真正的问题是,鉴于大部分信息都是文本的,你将如何执行命令
  • “我如何获取一个巧妙构造的字符串,该字符串实际上包含我想要运行的代码,然后让 Java 运行它?Java 的语法是什么?” - 什么这个“巧妙构造的字符串”究竟长什么样子?是 JavaScript、Java 代码还是你自己的发明?
  • @MadProgrammer 您说“与创建静态菜单没有什么不同”。好的,那么如何指定我应用实例化等构造的名称?您能否给出“JMenuItem = new JMenuItem();”的示例语法或“.setFont(myFont);” ...作为一些简单的例子?如果是这样,请使用它来为我的问题创建答案!
  • @RichardT 如果您不想维护单个变量引用,请使用 HashMapList

标签: java swing dynamic jmenu jmenuitem


【解决方案1】:

如果我了解您的总体意图,那么我建议从 Actions API 开始,它用于创建独立的工作单元,这些单元独立于它们的显示方式。

这允许您定义可重用(或在您的情况下为动态)操作,这些操作可以通过菜单、工具栏、按钮甚至开箱即用的键绑定来执行。

因为设置Action 可能有点乏味,我可能会考虑使用构建器模式,但您不必这样做,如果您愿意,可以手动构建它们;)

public class ActionBuilder {
    private ActioBuilderAction action;

    public ActionBuilder() {
        action = new ActionBuilder.ActioBuilderAction();
    }

    public ActionBuilder toolTip(String text) {
        action.putValue(Action.SHORT_DESCRIPTION, text);
        return this;
    }

    public ActionBuilder command(String text) {
        action.putValue(Action.ACTION_COMMAND_KEY, text);
        return this;
    }

    public ActionBuilder mnemonic(int key) {
        action.putValue(Action.MNEMONIC_KEY, key);
        return this;
    }

    public ActionBuilder displayedMnemonicIndex(int index) {
        action.putValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY, index);
        return this;
    }

    public ActionBuilder text(String text) {
        action.putValue(Action.NAME, text);
        return this;
    }

    public ActionBuilder smallIcon(Icon icon) {
        action.putValue(Action.SMALL_ICON, icon);
        return this;
    }

    public ActionBuilder largeIcon(Icon icon) {
        action.putValue(Action.LARGE_ICON_KEY, icon);
        return this;
    }

    public ActionBuilder acceleratorKey(KeyStroke ks) {
        action.putValue(Action.ACCELERATOR_KEY, ks);
        return this;
    }

    public ActionBuilder actionListener(ActionListener listener) {
        action.setListener(listener);
    }

    public Action build() {
        return action;
    }

    public class ActioBuilderAction extends AbstractAction {

        private ActionListener listener;

        public void setListener(ActionListener listener) {
            this.listener = listener;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (listener != null) {
                listener.actionPerformed(e);
            }
        }

    }
}

然后,您可以简单地构建一个新菜单,例如...

Action action = new ActionBuilder().text("Super awesome command").actionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Super aweseom comand GO!");
    }
}).build();

JMenuItem mi = new JMenuItem(action);

现在,我想,你可能有某种“命令执行器”类,它会。物理执行命令。我会创建一个实现ActionListener 的桥接类,当它被调用时,会执行指定的命令

public class CommandListener implements ActionListener {
    private String command;

    public CommandListener(String command) {
        this.command = command;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        CommandExecutor executor = new CommandExecutor();
        executor.execute(command)
    }


}

这可以用来代替第一个示例中的ActionListener...

Action action = new ActionBuilder().text(commandName).actionListener(new CommandListener(command)).build();

总体思路

【讨论】:

  • 这看起来很有创意,虽然可能有点麻烦,但远不如将代码写入要编译的文件等等......(我认为这是可行的,但并不容易!)......所以,这值得我做更多的研究——到目前为止,我对“Actions API”一无所知! ...顺便说一句,我不明白您上面关于“维护单个变量引用”的评论。 ...有很多方法可以跟踪名称,这是“取消引用”部分,其中变量的内容被视为代码,这是一个大技巧(而且,我认为,Java 设计中的一个大漏洞)。
  • @RichardT 是也不是。部分问题是需要将代码“编译”为字节码,以及 API 引用和其他可能的问题。 Java 确实允许您通过自定义类加载甚至compile and load it 在运行时加载类,虽然它肯定不是“漂亮”,但围绕它构建一个包装 API 并不难。
  • @RichardT 对于不需要Java库的工作,你也可以执行JavaScript
  • 是的,我理解字节码问题,但更明智的 Java 设计会预见到这种需求,并将动态字节码创建作为架构的核心部分融入当前上下文。这当然是可行的,但不是“凡人”。 (如果我有毕生精力致力于这项任务,或者我曾在最初的开发团队中,我相信我可以做到这一点。)......是的,我过去做过一些 API 包装,你'是对的,但仍然有很多工作要做。最后,它需要在已经运行的代码的上下文中工作 - 完整的 Java。
  • 就我个人而言,我会使用样式框架中的插件,其中预编译的代码单元可以在运行时加载到应用程序中并执行,但这只是我
猜你喜欢
  • 1970-01-01
  • 2015-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
  • 1970-01-01
  • 2014-04-25
相关资源
最近更新 更多