如何让Java 7应用程序将其菜单栏放在屏幕顶部(在Mac上)并且还有正确工作的键盘快捷键?
我有一个带有Swing用户界面的Java应用程序。许多菜单都有等效的键盘,这是必不可少的。
很少有系统依赖,但在Mac OS X上,菜单栏应显示在屏幕顶部而不是每个窗口上,因此我设置了apple.laf.useScreenMenuBar
。
这在Java 6上运行正常,但在Java 7上(上周出来!)编译并运行相同的代码会导致键盘快捷键执行两次菜单操作。例如,在附加的代码中,Command⌘ + O 打开两个文件对话框而不是一个。 (其他键盘快捷键也会动作两次,但有时你必须移动窗口才能看到它们。)
如果我没有设置apple.laf.useScreenMenuBar
,键盘问题就会消失,如果必须的话,那就是我要做的,但我的Mac用户会不高兴。我真的很想让菜单栏在正确的位置,键盘快捷键正常工作。
系统:2010年末MacBook Pro上的Mac OS 10.7.3(Lion)
Java 7:
java版“1.7.0_04”
Java(TM)SE运行时环境(版本1.7.0_04-b21)
Java HotSpot(TM)64位服务器VM(版本23.0-b21,混合模式)
Java 6:
java版“1.6.0_31”
Java(TM)SE运行时环境(版本1.6.0_31-b04-415-11M3635)
Java HotSpot(TM)64位服务器VM(版本20.6-b01-415,混合模式)
我看过的地方:
why apple.laf.useScreenMenuBar
should be gotten rid of的讨论
- 我全力以赴,但似乎没有发生过。
关于not using mrj.version
to detect that you're on a Mac的讨论
- 没有直接相关,但听起来很有希望。
我为所附代码的长度(148行)道歉,但我的Swing编码非常老式。它应该在没有任何特殊标志或设置的情况下从命令行编译和运行。
import javax.swing.*;
import java.awt.Toolkit;
import java.awt.*;
import java.awt.event.*;
/**
* Shows that using the single screen-top menu bar on a Mac with Java 7
* causes keyboard shortcuts to act twice.
*
* To see the problem(on a Mac -- running OS X 10.7.3 in my case):
* 1) compile on either Java 6 or Java 7
* 2) run on Java 7
* 3) give the command-O shortcut
* You will see two file dialogues.
*
* -- J. Clarke, May 2012
*/
public class MenuBug {
private static void go(String[] args) {
// Comment out the following line to fix the problem;
// leave it active to see the problem.
// It doesn't help to ...
// ... put the line into a static block.
// ... put the line right after the setLookAndFeel call.
// ... put the line before after the setLookAndFeel call.
System.setProperty("apple.laf.useScreenMenuBar", "true");
MainWindow mainWindow = new MainWindow();
}
public static void main(final String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {
JOptionPane.showMessageDialog(null,
e + " while loading look and feel",
"MenuBug error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
go(args);
}
});
}
}
class MainWindow extends JFrame {
MainWindow() {
super ("Main Window");
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener (new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
});
JMenuBar menuBar = createMenuBar();
setJMenuBar(menuBar);
pack();
setSize(350,300);
setVisible(true);
}
private JMenuBar createMenuBar() {
JMenuBar mBar = new JMenuBar();
JMenu menu = new JMenu("File");
String[] menuItemNames = new String[] {"New", "Open...", "Other"};
for (int i = 0; i < menuItemNames.length; i++) {
String miName = menuItemNames[i];
JMenuItem mi = new JMenuItem(miName);
mi.setActionCommand(miName);
linkMenuItemToAction(mi);
menu.add(mi);
}
mBar.add(menu);
return mBar;
}
/**
* Create an Action for menuItem, and make sure the action and the menu
* item know about each other; where appropriate, add keyboard equivalents.
* @param menuItem The menu item to be linked to an action.
*/
private void linkMenuItemToAction(JMenuItem menuItem) {
final int META_MASK =
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
Action a = null;
String miName = menuItem.getActionCommand();
if (miName.equals ("New")) {
a = new NewAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
META_MASK));
}
else if (miName.equals ("Open...")) {
a = new OpenAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
META_MASK));
}
else if (miName.equals ("Other")) {
a = new OtherAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T,
META_MASK));
}
menuItem.setEnabled(a.isEnabled());
menuItem.addActionListener(a);
}
private class NewAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
new MainWindow();
}
}
private void makeDialog() {
String dialogTitle = "Please choose a file to open";
FileDialog fileDialog = new FileDialog(this, dialogTitle,
FileDialog.LOAD);
fileDialog.setVisible(true);
String fileName = fileDialog.getFile();
}
private class OpenAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
makeDialog();
}
}
private class OtherAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null,
"an example message",
"not really an error", JOptionPane.ERROR_MESSAGE);
}
}
}
答案 0 :(得分:4)
我正在回答我自己的问题 - 有点像。正如原始评论中所指出的那样,Java 1.7u10就会出现麻烦。
答案 1 :(得分:0)
看起来这个问题仍然存在,但现在可以用1.7_21在Mac上使用fn + backSpace(删除)进行复制。
我使用了与上面相同的例子,只添加了文本字段。在文本字段中选择部分文本,然后按删除(fn +退格键)
在linkMenuItemToAction方法
中将KeyStroke更改为“DELETE”else if (miName.equals ("Other"))
{
a = new OtherAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke("DELETE"));
}
并添加:
JTextField textField = new JTextField(10);
textField.setText("Long long long long long long long text");
add(textField, BorderLayout.PAGE_START);
到MainWindow构造函数。