使用Nimbus LAF的Mac键盘快捷键

5

有没有办法在OS X上使用Nimbus LAF(外观和感觉),同时仍然能够使用Meta键进行剪切/复制/粘贴和全选操作?

我目前在我的Swing应用程序的主方法中使用以下代码,根据操作系统更改LAF(对于OS X默认值,对于所有其他操作系统使用Nimbus):

if (!System.getProperty("os.name", "").startsWith("Mac OS X")) {
    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException ex) {
        java.util.logging.Logger.getLogger(LicenseInspectorUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        java.util.logging.Logger.getLogger(LicenseInspectorUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        java.util.logging.Logger.getLogger(LicenseInspectorUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(LicenseInspectorUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }
}

我这样做是因为Nimbus在Mac OS X上覆盖了剪切/复制/粘贴和全选的键盘快捷方式(Meta键与Ctrl键)。 我希望一直使用Nimbus,只要键盘快捷方式没有被覆盖掉就可以了。
2个回答

3
使用getMenuShortcutKeyMask()方法与NimbusLookAndFeel一起使用,以启用键,如此示例所示。另请参见此相关答案
在特定情况下,对于JTextField,您可以在键绑定中使用该掩码来调用原始操作。
int MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
JTextField jtf = new JTextField("Test");
jtf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, MASK), "select-all");
jtf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, MASK), "copy");
jtf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_X, MASK), "cut");
jtf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_V, MASK), "paste");

我不认为这回答了问题。即使在注册自定义键盘快捷方式时调用getMenuShortcutKeyMask(),这也无法解决在OSX上使用NimbusLookAndFeel时默认的Swing TextField中出现的Ctrl-C、Ctrl-V等不正确的问题。 - yonran
@yonran:我已经详细阐述了上面的内容。 - trashgod
似乎每个组件的操作名称都不同。因此,要映射“复制”操作,您还需要映射DefaultEditorKit.copyAction。 - Jouni Aro
@JouniAro:并非如此;这些操作已经存在于文本字段的“ActionMap”中,在UI代理的初始化过程中(通过名称)放置在那里,请参见此文章 - trashgod
1
抱歉,我的意思是每个组件类型都有一个。因此,对于每个表格,ActionMap 包含“复制”,而对于每个文本字段,它包含“复制到剪贴板”(=DefaultEditorKit.copyAction)。 - Jouni Aro

1
不同的组件使用不同的键,因此要映射所有组件,您需要定义不同的键。例如(基础内容在这里找到):
private void addOSXKeyStrokes(InputMap inputMap) {
  inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.META_DOWN_MASK), DefaultEditorKit.copyAction);
  inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.META_DOWN_MASK), DefaultEditorKit.cutAction);
  inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction);
  inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.META_DOWN_MASK), DefaultEditorKit.selectAllAction);
  inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.META_DOWN_MASK), "copy");
  inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.META_DOWN_MASK), "selectAll");
}

这可以按照以下方式映射到不同的组件:
// This must be performed immediately after the LaF has been set
if (System.getProperty("os.name", "").startsWith("Mac OS X")) {
  // Ensure OSX key bindings are used for copy, paste etc
  // Use the Nimbus keys and ensure this occurs before any component creation
  addOSXKeyStrokes((InputMap) UIManager.get("EditorPane.focusInputMap"));
  addOSXKeyStrokes((InputMap) UIManager.get("FormattedTextField.focusInputMap"));
  addOSXKeyStrokes((InputMap) UIManager.get("PasswordField.focusInputMap"));
  addOSXKeyStrokes((InputMap) UIManager.get("TextField.focusInputMap"));
  addOSXKeyStrokes((InputMap) UIManager.get("TextPane.focusInputMap"));
  addOSXKeyStrokes((InputMap) UIManager.get("TextArea.focusInputMap"));
  addOSXKeyStrokes((InputMap) UIManager.get("Table.ancestorInputMap"));
  addOSXKeyStrokes((InputMap) UIManager.get("Tree.focusInputMap"));
}

这里有完整的 Aqua(OS X外观)操作名称列表(链接)


源链接赞! - trashgod
谢谢。我花了很长时间才找到一个清晰的例子,所以我想在这里分享它 - 并加上我的补充。 - Jouni Aro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接