2012-05-01 4 views
0

Java 7アプリケーションのメニューバーを(Mac上の)画面上部に表示させるにはどうしたらいいですか?また、正しく動作するキーボードショートカットもありますか?Java 7、Mac OSのキーボード対メニューの競合

私はSwingユーザーインターフェイスを持つJavaアプリケーションを持っています。多くのメニューには、キーボードに相当するものがあります。

システムに依存するものはほとんどありませんが、Mac OS Xではメニューバーは各ウィンドウではなく画面の上部に表示されるため、apple.laf.useScreenMenuBarと設定します。

これはJava 6でもうまく動作しますが、先週のJava 7では、同じコードをコンパイルして実行するとキーボードショートカットでメニューアクションが2回実行されます。たとえば、添付のコードでは、コマンド⌘ + は、1つではなく2つのファイルダイアログを開きます。 (他のキーボードショートカットも2回動作しますが、ときどきウィンドウを移動しなければならないことがあります)

apple.laf.useScreenMenuBarを設定しないとキーボードの問題が消えてしまいます。私のMacユーザーは不快に思うだろう。私は本当に適切な場所にメニューバーを持っていて、キーボードショートカットがうまくいきたいと思っています。


システム:上のMac OS 10.7.3(ライオン)後半-2010 MacBook Proの

のJava 7:
Javaのバージョン "1.7.0_04"
のJava(TM) SEランタイム環境(1.7.0_04-B21を構築)
は、Java HotSpot(TM)64ビットサーバーVM(23.0-B21、混合モードを構築する)

ジャVA 6:
Javaのバージョン "1.6.0_31"
のJava(TM)SE Runtime Environmentに
は、Java HotSpot(TM)64ビットサーバーVM(1.6.0_31-b04-415-11M3635を構築)(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

(参考にしてくれたQwerty Bobに感謝します。私は本当にもっと見て、自分でやっていたはずです)私はこの質問を他の場所で聞いています。 –

+0

更新:キーボードショートカットが機能するようになりましたが、メニューには表示されません!私は新しい7u7リリースを試している間にこれを発見しましたが、新しいバグはすでに7u6のために報告されているようです。(http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7186371) 私はMountain Lion(Mac OS X 10.8.1)にもアップデートしましたが、Lionシステムのクイックチェックでは、OSの変更ではなく、Javaリリースが原因であることがわかりました。 –

+0

アップデート:メニューにキーボードショートカットの表示を含むJava 1.7u10がこれを修正しました。私は現在OS X 10.8.2を使用していますが、他のバージョンのものもOKです。 –

答えて

4

私は自分自身の質問に答えています。オリジナルのコメントに書かれているように、Java 1.7u10では問題はなくなりました。

0

この問題はまだ残っているようですが、今は1.7_21のMacでfn + backSpace(delete)を使って再現できます。

私は上記と同じ例を使用してテキストフィールドを追加しました。メインウィンドウのコンストラクタに

JTextField textField = new JTextField(10); 
textField.setText("Long long long long long long long text"); 
add(textField, BorderLayout.PAGE_START); 

:linkMenuItemToAction方法で

else if (miName.equals ("Other")) 
{ 
a = new OtherAction(); 
menuItem.setAccelerator(KeyStroke.getKeyStroke("DELETE")); 
} 

を "DELETE" とこれを追加するために変更したKeyStroke

テキストフィールドとプレスでテキストの一部を選択します(FN +バックスペース)を削除します。