在OS X上使用屏幕菜单栏时,如何使菜单项加速键正常工作

时间:2016-05-18 11:00:58

标签: java macos swing jmenubar

在OS X上,从主JMenuBar中删除JFrame并使用屏幕菜单栏是有意义的。

我的印象是,在Apple JDK的最新版本中,这是使用

完成的
Application.getApplication().setDefaultMenuBar( JMenuBar );

呼叫。

使用此功能时,似乎加速键不再有效。

以下程序说明了OS X上的问题:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import com.apple.eawt.Application;

public class MacMenuBarShortcutTest {
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override
      public void run() {
        showUI();
      }
    });
  }

  private static void showUI(){
    JFrame testFrame = new JFrame("TestFrame");

    JLabel content = new JLabel("Press cmd-t to test whether the action is triggered");
    testFrame.getContentPane().add(content);

    JMenuBar menuBar = new JMenuBar();

    Action action = new AbstractAction() {
      @Override
      public void actionPerformed(ActionEvent e) {
        JOptionPane.showMessageDialog(null, "It works!");
      }
    };
    action.putValue(Action.NAME, "Test action");
    action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
    JMenu menu = new JMenu("Menu");
    menu.add(new JMenuItem(action));
    menuBar.add(menu);

    Application.getApplication().setDefaultMenuBar(menuBar);

    testFrame.setVisible(true);
    testFrame.pack();
    testFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
  }
}

程序应该允许你按 cmd + t 并弹出一个对话框,确认动作的快捷方式有效。

然而这不起作用。按下快捷键时,菜单项会突出显示,但不会执行操作。

我没有在com.apple.eawt.Application课程上找到任何我忘记打电话的相关方法。在rather outdated article on the Apple website中查看代码表明快捷方式应该正常工作。

请注意,使用时

System.setProperty("apple.laf.useScreenMenuBar", "true")

而不是Application#setDefaultMenuBar方法,它按预期工作。这是否意味着系统属性仍然是推荐的方式,我不应该在Application类上使用该方法?

1 个答案:

答案 0 :(得分:1)

我混合了两件不同的东西:

系统属性

null

确定Aqua外观是否使用顶级窗口的菜单栏(例如System.setProperty("apple.laf.useScreenMenuBar", "true") )作为应用程序菜单栏。

将此设置为JFrame将确保您致电时提供例如。

true

当框架具有焦点时,菜单栏将用作应用程序菜单栏,并且菜单栏永远不会被绘制为JFrame frame = ...; JMenuBar menu = ...; frame.setJMenuBar(menu); 的一部分。 当另一个帧(或顶级组件)获得焦点时,应用程序菜单栏将更新以显示该组件的菜单栏。

例如,当您使用JFrame方法之一显示模式对话框时,应用程序菜单栏将尝试显示该模式对话框的菜单栏。由于这是JOptionPane.showXXX,只要该模式对话框未关闭,应用程序菜单栏就会变为空。

这是null方法发挥作用的地方。如果您使用非Application.setDefaultMenuBar菜单栏调用此方法,则当没有菜单栏的顶级组件获得焦点时,该菜单栏将显示为应用程序菜单栏

因此,问题中的片段有两个问题:

  • 它不会将系统属性设置为true
  • 仅设置默认菜单栏,并忘记在null上设置菜单栏。由于JFrame本身没有菜单栏,因此会显示默认菜单栏,这样会给人的印象是JFrame方法是系统属性的替代方法。但事实显然并非如此。

结果是快捷方式无效,因为setDefaultMenuBar中未包含JMenuBar