在 OS X 上使用屏幕菜单栏时如何使菜单项加速键起作用
How to get the menu item accelerator keys working when using the screen menu bar on OS X
在 OS X 上,从主 JFrame
中删除 JMenuBar
并改用屏幕菜单栏是有意义的。
我的印象是,在最新版本的 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
class上没有找到相关的方法,忘记调用了。查看 rather outdated article on the Apple website 中的代码表明快捷方式应该可以正常工作。
注意使用
时
System.setProperty("apple.laf.useScreenMenuBar", "true")
而不是 Application#setDefaultMenuBar
方法,它按预期工作。这是否意味着系统 属性 仍然是推荐的方法,我不应该使用 Application
class 上的方法?
我混合了两种不同的东西:
系统属性
System.setProperty("apple.laf.useScreenMenuBar", "true")
确定 Aqua 外观是否使用顶级 window(例如 JFrame
)的菜单栏作为应用程序菜单栏。
将此设置为 true
将确保当您调用
JFrame frame = ...;
JMenuBar menu = ...;
frame.setJMenuBar(menu);
当框架有焦点时,菜单栏将用作应用程序菜单栏,并且菜单栏永远不会被绘制为 JFrame
的一部分。
当另一个框架(或顶级组件)获得焦点时,应用程序菜单栏将更新以显示该组件的菜单栏。
例如,当您使用 JOptionPane.showXXX
方法之一显示模态对话框时,应用程序菜单栏将尝试显示该模态对话框的菜单栏。因为这是null
,所以只要模态对话框没有关闭,应用程序菜单栏就会变成空的。
这就是 Application.setDefaultMenuBar
方法发挥作用的地方。如果您使用非 null
菜单栏调用此方法,则当没有菜单栏的顶级组件获得焦点时,该菜单栏将显示为应用程序菜单栏 。
因此,问题中的片段有 2 个问题:
- 它没有将系统 属性 设置为 true
- 只设置了默认菜单栏,忘记设置
JFrame
上的菜单栏了。因为 JFrame
本身没有菜单栏,所以显示默认菜单栏,给人的印象是 setDefaultMenuBar
方法是系统 属性 的替代方法。但显然不是这样。
结果是快捷方式不起作用,因为 JMenuBar
不包含在 JFrame
中。
在 OS X 上,从主 JFrame
中删除 JMenuBar
并改用屏幕菜单栏是有意义的。
我的印象是,在最新版本的 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
class上没有找到相关的方法,忘记调用了。查看 rather outdated article on the Apple website 中的代码表明快捷方式应该可以正常工作。
注意使用
时System.setProperty("apple.laf.useScreenMenuBar", "true")
而不是 Application#setDefaultMenuBar
方法,它按预期工作。这是否意味着系统 属性 仍然是推荐的方法,我不应该使用 Application
class 上的方法?
我混合了两种不同的东西:
系统属性
System.setProperty("apple.laf.useScreenMenuBar", "true")
确定 Aqua 外观是否使用顶级 window(例如 JFrame
)的菜单栏作为应用程序菜单栏。
将此设置为 true
将确保当您调用
JFrame frame = ...;
JMenuBar menu = ...;
frame.setJMenuBar(menu);
当框架有焦点时,菜单栏将用作应用程序菜单栏,并且菜单栏永远不会被绘制为 JFrame
的一部分。
当另一个框架(或顶级组件)获得焦点时,应用程序菜单栏将更新以显示该组件的菜单栏。
例如,当您使用 JOptionPane.showXXX
方法之一显示模态对话框时,应用程序菜单栏将尝试显示该模态对话框的菜单栏。因为这是null
,所以只要模态对话框没有关闭,应用程序菜单栏就会变成空的。
这就是 Application.setDefaultMenuBar
方法发挥作用的地方。如果您使用非 null
菜单栏调用此方法,则当没有菜单栏的顶级组件获得焦点时,该菜单栏将显示为应用程序菜单栏 。
因此,问题中的片段有 2 个问题:
- 它没有将系统 属性 设置为 true
- 只设置了默认菜单栏,忘记设置
JFrame
上的菜单栏了。因为JFrame
本身没有菜单栏,所以显示默认菜单栏,给人的印象是setDefaultMenuBar
方法是系统 属性 的替代方法。但显然不是这样。
结果是快捷方式不起作用,因为 JMenuBar
不包含在 JFrame
中。