2016-03-10 8 views
1

J'ai créé une petite application en utilisant Netbeans 8.1 sur OSX. Il contient juste deux menus "fichier" et "éditer". Le but est d'ajouter la fonctionnalité copier/couper/coller au menu d'édition plus tard. Je veux utiliser constructeur NetBeans GUI mais je rencontre les problèmes suivants:Java sur OSX: icône de la mauvaise touche d'accélération dans le menu Swing à l'aide du générateur d'interface graphique Netbeans

1er essai:

J'ai créé un petit exemple avec le constructeur NetBeans GUI (GUI Swing Forms -> JDialog). Je viens d'ajouter une barre de menu au JFrame et un JMenuItem dans le générateur GUI et du code au constructeur. Le résultat est:

enter image description here

Comme vous pouvez le voir je reçois un texte « méta » au lieu de la touche Pomme « de ⌘ ».

Le code source est NewJDialogGUI.java:

import java.awt.Toolkit; 
import java.awt.event.KeyEvent; 
import javax.swing.AbstractAction; 
import javax.swing.Action; 
import javax.swing.KeyStroke; 
import javax.swing.text.DefaultEditorKit; 

public class NewJDialogGUI extends javax.swing.JDialog { 
    private static final int MASK 
     = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); 

    public NewJDialogGUI(java.awt.Frame parent, boolean modal) { 
     super(parent, modal); 

     initComponents(); 

     AbstractAction copyAction = new DefaultEditorKit.CopyAction(); 
     copyAction.putValue(Action.ACCELERATOR_KEY,KeyStroke.getKeyStroke(KeyEvent.VK_C, MASK)); 


     this.jMenuItem1.setAction(copyAction); 
     this.jMenuItem1.setText("Copy"); 
     this.jMenuItem1.setMnemonic(KeyEvent.VK_C); 

    } 

    @SuppressWarnings("unchecked") 
    // <editor-fold defaultstate="collapsed" desc="Generated Code">       
    private void initComponents() { 

     jMenuBar1 = new javax.swing.JMenuBar(); 
     jMenu1 = new javax.swing.JMenu(); 
     jMenu2 = new javax.swing.JMenu(); 
     jMenuItem1 = new javax.swing.JMenuItem(); 

     setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); 

     jMenu1.setText("File"); 
     jMenuBar1.add(jMenu1); 

     jMenu2.setText("Edit"); 

     jMenuItem1.setText("jMenuItem1"); 
     jMenu2.add(jMenuItem1); 

     jMenuBar1.add(jMenu2); 

     setJMenuBar(jMenuBar1); 

     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 
     getContentPane().setLayout(layout); 
     layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGap(0, 400, Short.MAX_VALUE) 
     ); 
     layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGap(0, 278, Short.MAX_VALUE) 
     ); 

     pack(); 
    }// </editor-fold>       


    public static void main(String args[]) { 
     /* Set the Nimbus look and feel */ 
     //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> 
     /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. 
     * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
     */ 
     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(NewJDialogGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
     } catch (InstantiationException ex) { 
      java.util.logging.Logger.getLogger(NewJDialogGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
     } catch (IllegalAccessException ex) { 
      java.util.logging.Logger.getLogger(NewJDialogGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
     } catch (javax.swing.UnsupportedLookAndFeelException ex) { 
      java.util.logging.Logger.getLogger(NewJDialogGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
     } 
     //</editor-fold> 

     /* Create and display the dialog */ 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       NewJDialogGUI dialog = new NewJDialogGUI(new javax.swing.JFrame(), true); 
       dialog.addWindowListener(new java.awt.event.WindowAdapter() { 
        @Override 
        public void windowClosing(java.awt.event.WindowEvent e) { 
         System.exit(0); 
        } 
       }); 
       dialog.setVisible(true); 
      } 
     }); 
    } 

    private javax.swing.JMenu jMenu1; 
    private javax.swing.JMenu jMenu2; 
    private javax.swing.JMenuBar jMenuBar1; 
    private javax.swing.JMenuItem jMenuItem1;     
} 

Et le NewJDialogGUI.form:

<?xml version="1.0" encoding="UTF-8" ?> 

<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo"> 
    <NonVisualComponents> 
    <Menu class="javax.swing.JMenuBar" name="jMenuBar1"> 
     <SubComponents> 
     <Menu class="javax.swing.JMenu" name="jMenu1"> 
      <Properties> 
      <Property name="text" type="java.lang.String" value="File"/> 
      </Properties> 
     </Menu> 
     <Menu class="javax.swing.JMenu" name="jMenu2"> 
      <Properties> 
      <Property name="text" type="java.lang.String" value="Edit"/> 
      </Properties> 
      <SubComponents> 
      <MenuItem class="javax.swing.JMenuItem" name="jMenuItem1"> 
       <Properties> 
       <Property name="text" type="java.lang.String" value="jMenuItem1"/> 
       </Properties> 
      </MenuItem> 
      </SubComponents> 
     </Menu> 
     </SubComponents> 
    </Menu> 
    </NonVisualComponents> 
    <Properties> 
    <Property name="defaultCloseOperation" type="int" value="2"/> 
    </Properties> 
    <SyntheticProperties> 
    <SyntheticProperty name="menuBar" type="java.lang.String" value="jMenuBar1"/> 
    <SyntheticProperty name="formSizePolicy" type="int" value="1"/> 
    <SyntheticProperty name="generateCenter" type="boolean" value="false"/> 
    </SyntheticProperties> 
    <AuxValues> 
    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> 
    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> 
    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> 
    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> 
    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> 
    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> 
    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> 
    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> 
    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> 
    </AuxValues> 

    <Layout> 
    <DimensionLayout dim="0"> 
     <Group type="103" groupAlignment="0" attributes="0"> 
      <EmptySpace min="0" pref="400" max="32767" attributes="0"/> 
     </Group> 
    </DimensionLayout> 
    <DimensionLayout dim="1"> 
     <Group type="103" groupAlignment="0" attributes="0"> 
      <EmptySpace min="0" pref="278" max="32767" attributes="0"/> 
     </Group> 
    </DimensionLayout> 
    </Layout> 
</Form> 

2ème essai:

J'ai créé un autre petit exemple avec le constructeur NetBeans GUI (GUI swing Forms -> Formulaire d'exemple d'application). Le résultat est:

enter image description here

Même résultat comme dans le 1er essai.

3ème essai:

Enfin j'ai créé un exemple avec Netbeans (fichier vide Java) avec le code source légèrement modifiée de here. Le résultat est:

enter image description here

Le code source est:

import java.awt.EventQueue; 
import java.awt.Toolkit; 
import java.awt.event.KeyEvent; 
import javax.swing.AbstractAction; 
import javax.swing.Action; 
import javax.swing.JFrame; 
import javax.swing.JMenu; 
import javax.swing.JMenuBar; 
import javax.swing.JMenuItem; 
import javax.swing.JTextField; 
import javax.swing.KeyStroke; 
import javax.swing.text.DefaultEditorKit; 

/** 
* @see https://stackoverflow.com/a/34830519/230513 
*/ 
public class NewEmptyGUI { 

    private static final int MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); 

    private void display() { 
     JFrame f = new JFrame("Test"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     JMenuBar menuBar = new JMenuBar(); 
     JMenu menu = new JMenu("Edit"); 
     menu.setMnemonic(KeyEvent.VK_E); 
     JMenuItem menuItem = new JMenuItem(); 
     AbstractAction copyAction = new DefaultEditorKit.CopyAction(); 
     copyAction.putValue(Action.ACCELERATOR_KEY, 
       KeyStroke.getKeyStroke(KeyEvent.VK_C, MASK)); 
     menuItem.setAction(copyAction); 
     menuItem.setText("Copy"); 
     menu.add(menuItem); 
     menuBar.add(menu); 
     f.setJMenuBar(menuBar); 
     f.add(new JTextField(10)); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 


    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 

       new NewEmptyGUI().display(); 
      } 
     }); 
    } 
} 

Ceci est le résultat attendu, mais le menu entier Infrastrucures a été codé manuellement, ce qui est pas mon intention. Je veux utiliser Netbeans GUI Builder. Avez-vous des indices pour moi? Je suis en train d'utiliser JDK7 et OSX Yosemite. L'apparence et la sensation sont "Nimbus". Je ne colle que l'exemple de code ou le 1er et le 3ème essai ici, parce que c'est beaucoup de code.

+0

Merci pour un [mcve]; ajouter 'NewJDialogGUI.form' permettra aux autres de recréer votre exemple. – trashgod

+0

Trashgod, c'est sympa de ta part! J'ai mis à jour la question avec le 'NewJDialogGUI.form'. – Bebass

Répondre

1

J'ai trouvé des solutions pour le problème décrit.

Solution 1 (changement look and feel):

L'exemple de code montre comment remplacer le "look and feel Nimbus" dans le code créé Netbeans.Il mettra également les raccourcis clavier corrects pour les actions presse-papiers comme copier & coller avec la touche Apple « de ⌘ » au lieu du « contrôle-clé » automatiquement:

public static void main(String args[]) { 

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


    java.awt.EventQueue.invokeLater(new Runnable() { 
     public void run() { 
      new App_Avaprism().setVisible(true); 
     } 
    }); 

Solution 2:

Si vous voulez rester avec "Nimbus" les choses deviennent plus difficiles. Au début: je n'ai trouvé aucun moyen de remplacer le texte 'meta'. Au moins, vous voudrez peut-être que les raccourcis du presse-papiers fonctionnent avec la touche Apple '⌘'.

Pour votre application principale mettre le code suivant dans le constructeur:

int MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); 

InputMap im = (InputMap) UIManager.get("TextField.focusInputMap"); 
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, MASK), DefaultEditorKit.copyAction); 
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, MASK), DefaultEditorKit.pasteAction); 
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, MASK), DefaultEditorKit.cutAction); 

Malheureusement: Si vous commencez à d'autres boîtes de dialogue modales de cette application principale les raccourcis ne fonctionneront pas. Dans ce cas, vous pouvez essayer d'utiliser KeyEventDispatcher pour établir une redirection globale des séquences de touches pour l'ensemble de l'application. Plus d'informations à ce sujet peuvent être trouvés here et here.

+0

La solution '1' est la valeur par défaut, donc inutile; la solution '2' est la bonne façon de faire que' com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel' utilise le 'MASK' que' com.apple.laf.AquaLookAndFeel' utilise par défaut; plus un pour les ressources utiles. – trashgod

+0

Étonnamment je trouve dans le code généré par Netbeans 'if (" Nimbus ".equals (info.getName()))' au lieu de 'if (" Mac OS X ".equals (info.getName()))' bien que le GUI builder avait montré "aqua l & f" dans l'aperçu et je cours Netbeans sous OSX. Donc vous avez raison: ce devrait être le défaut sous OSX mais dans mon cas ce n'était pas le cas. Pourriez-vous vérifier ce que Netbeans génère dans votre cas par défaut? – Bebass

+0

Ah, je vois la différence: 'com.apple.laf.AquaLookAndFeel' est la valeur par défaut avec aucun code d'initialisation, alors que le code pour définir' com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel' (si disponible) est la valeur par défaut pour le code généré. – trashgod