java - 当所有项目都被禁用时禁用 JMenu

标签 java swing jmenu

我试图在 JMenu 的所有子项都被禁用时禁用它。 我有一个“添加新”菜单,在这个菜单中有两个菜单项:"file"和“目录”。

菜单项绑定(bind)到我更改其状态的特定操作,因此菜单项也会更改它们的状态。

我想要实现的是,当"file"和“目录”操作以及项目都被禁用时,“添加新”菜单被禁用。

我试图覆盖 JMenu 的 isSelected() 方法,但它部分起作用了——它不显示项目。但是,菜单仍被绘制为 Activity 状态(黑色字体而不是灰色)。

关于如何实现这一点有什么想法吗?

这是一个复制情况的代码示例:

public static void main(String args[]) {
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() { 

            JFrame frame = new JFrame();
            JPopupMenu popup = new JPopupMenu();

            final Action actionBeep = new DefaultEditorKit.BeepAction();
            final Action actionPaste = new DefaultEditorKit.PasteAction();

            JMenu menu = new JMenu("Add");
            menu.add(new JMenuItem(actionBeep));
            menu.add(new JMenuItem(actionPaste));
            popup.add(menu);

            JTable table = new JTable(3, 3);

            table.setComponentPopupMenu(popup);
            table.addMouseListener(new MouseAdapter() {
               @Override
               public void mouseReleased(MouseEvent e) {
                   if(e.getClickCount() == 2) {
                       actionBeep.setEnabled(!actionBeep.isEnabled());
                       actionPaste.setEnabled(!actionPaste.isEnabled());
                   }
               }
            });

            frame.add(table);
            frame.pack();
            frame.setVisible(true);

        }
    });
}

最佳答案

一个容易被遗忘的事实是,JMenu 是一个 AbstractButton,因此您可以为其设置一个 Action。虽然从未调用该 Action 的 actionPerformed,但它的属性用于使菜单的相应属性保持同步。

因此,假设您的所有菜单都由(组)Action 驱动,您可以定义一个包装器 Action,将其自己的启用状态同步到这样一个组,然后将该包装器设置到菜单。这种方法的优点是您可以

  • 重新使用这样的包装器 f.i.如果在主菜单和弹出窗口中应用相同的分组
  • 构建组树

包装器可能是这样的:

/**
 * Empty Action with enabled state that's the OR'ed enabled of all contained actions.
 */
public static class OrEnabledEmptyAction extends AbstractAction {

    private List<Action> actions;

    public OrEnabledEmptyAction(Collection<Action> actions, String name) {
        super(name);
        this.actions = new ArrayList<>(actions);
        installEnabledListener();
        updateEnabled();
    }

    /**
     * Updates this Action's enabled state dependent on enabled of
     * contained actions.
     */
    private void updateEnabled() {
        boolean enabled = false;
        for (Action action : actions) {
            enabled |= action.isEnabled();
        }
        setEnabled(enabled);
    }

    /**
     * Installs a PropertyChangeListener which updates this Action's 
     * enabled state on notification of enabled of contained actions.
     */
    private void installEnabledListener() {
        PropertyChangeListener l = new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if ("enabled".equals(evt.getPropertyName()))
                    updateEnabled();
            }

        };
        for (Action action : actions) {
            action.addPropertyChangeListener(l);
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // does nothing, never called for a JMenu anyway
    }

}

它的用法(你的例子有一个额外的 mainMenu 来突出重用):

JPopupMenu popup = new JPopupMenu();

final Action actionBeep = new DefaultEditorKit.BeepAction();
final Action actionPaste = new DefaultEditorKit.PasteAction();

final List<Action> actions = new ArrayList<>();
actions.add(actionBeep);
actions.add(actionPaste);
JMenu menu = new JMenu();
// add actions to menu in popup
for (Action action : actions) {
    menu.add(action);
}
// sets the menu's action to the OR-Enabled
menu.setAction(new OrEnabledEmptyAction(actions, "Add"));
popup.add(menu);

JMenuBar bar = new JMenuBar();
JMenu mainMenu = new JMenu();
// add actions to menu in menuBar
for (Action action : actions) {
    mainMenu.add(action);
}
// re-use or-action
mainMenu.setAction(menu.getAction());
bar.add(mainMenu);
frame.setJMenuBar(bar);

JTable table = new JTable(3, 3);

table.setComponentPopupMenu(popup);
// for seeing the effect, change enabled state of only one action
// per released
table.addMouseListener(new MouseAdapter() {
    int index;
    @Override
    public void mouseReleased(MouseEvent e) {
        if (!SwingUtilities.isLeftMouseButton(e))
            return;
        actions.get(index).setEnabled(!actions.get(index).isEnabled());
        index = (index +1) % actions.size();
    }
});

关于java - 当所有项目都被禁用时禁用 JMenu,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20951032/

相关文章:

java - setDefaultLookAndFeelDecorated 影响 JFrame 调整大小行为

java - 如何将 JMenu 的弹出窗口居中?

无法对任务进行排队的 Java 执行器

Java - 对象状态在方法调用后不会改变

java - 无法显示 JList

java - 选中时显示 JTable 行的信息

java - 单击 jmenu 时调用 actionperformed 方法

Java/Swing/Mac OSX : Converting JMenu to JPopupMenu using ScreenMenuBar

java - 如何将多个参数传递给 Saxon ExtensionFunction?

java - ModelMapper 转换器 - 不工作