Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Swing - Utilisation d'actions pour vos éléments de menu

Mise en oeuvre d'un menu contextuel Utilisation de JRadioButton



Accès rapide :
La vidéo
Pourquoi utiliser des actions Swing ?
Comment utiliser des actions Swing ?
Cacher le texte de l'action dans une barre d'outils
L'exemple de code complet

La vidéo

Une interface graphique propose des mécanismes standardisés pour déclencher vos traitements : barre de menu, barres d'outils, menus contextuels, ... Souvent une même action est disponible sur tous ces emplacements. Du coup, comment correctement factoriser la définitions des éléments rattachés à cette action (icône, mnémonique, accélérateur, ...) ? C'est à ce besoin que cherche à répondre le concept d'action Swing.


Utilisation d'actions pour vos éléments de menu

Pourquoi utiliser des actions Swing ?

Dans les trois chapitres précédents (Mise en oeuvre d'une barre de menu, Mise en oeuvre d'une barre d'outils et Mise en oeuvre d'un menu contextuel) nous avons appris à utiliser les principaux éléments de menu.

Le problème est que souvent une même fonctionnalité (dit autrement, une même action) est accessible à partir de la barre de menu, mais aussi à partir de la barre d'outils et enfin à partir d'un menu contextuel. De la manière dont nous avons travaillé, il est nécessaire de respecifier les icons, les accélérateurs, ... pour chaque élément de menu.

Le concept d'action Swing permet, justement, de répondre à cette problématique en factorisant en un seul endroit la définition du traitement de l'action (l'ActionListener), de son icône, son texte, ... Ensuite, on injecte cette action dans la barre de menu, dans la barre d'outil et dans un éventuel menu contextuel.

Comment utiliser des actions Swing ?

Le type de base, pour coder une action Swing, est l'interface javax.swing.Action qui étend l'interface java.awt.event.ActionListener : il sera donc nécessaire de redéfinir la méthode actionPerformed. Pour les autres méthodes abstraites de cette interface, ne vous inquiétez pas car nous n'aurons à les redéfinir. Effectivement, nous utiliserons la classe abstraite javax.swing.AbstractAction qui implémente l'interface initialement présentée.

Grace à la méthode putValue, vous pourrez associer à l'action une icône, un accélérateur, un mnémonique et son texte. Cela sera fait dans le constructeur de chacune de nos action. Voici un exemple de définition d'action pour notre élément de menu « New File... ».

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
private AbstractAction actNew = new AbstractAction() {
    {   // Le constructeur de votre classe anonyme
        putValue( Action.NAME, "New File" );
        putValue( Action.SMALL_ICON, new ImageIcon( "icons/new.png" ) );
        putValue( Action.MNEMONIC_KEY, KeyEvent.VK_N );
        putValue( Action.SHORT_DESCRIPTION, "New file... (CTRL+N)" );       // ToolTipText sur tool bar
        putValue( Action.ACCELERATOR_KEY,
                  KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK ) ); 
    }
    
    @Override public void actionPerformed( ActionEvent e ) {
        System.out.println( "New" );
    }
};
Exemple de définition d'une action
nous avons ici à faire à une implémentation d'une classe anonyme. Comme son nom l'indique cette classe n'a donc pas de nom. En conséquence, nous avons une difficulté : comment coder son constructeur ? Bonne question, me direz-vous ;-)
Et bien la syntaxe Java le permet. Il suffit simplement de mettre un bloc de code (entre accolades) telle quelle dans votre classe anonyme. Ce bloc sera bien considéré comme étant le constructeur de votre classe anonyme.

Ensuite, il ne reste plus qu'à utiliser cette action pour créer une élément de menu dans chaque conteneur considéré (barre de menu, barre d'outils ou menu contextuel).

 1 
 2 
 3 
JMenuItem mnuNew = mnuFile.add( actNew );
JButton btnNew = toolBar.add( actNew );
JMenuItem mnuNew2 = popupMenu.add( actNew );
Utilisation de l'action pour produire les éléments de menu

Et voici le résultat qui sera produit par l'exemple proposé ci-dessous.

Cacher le texte de l'action dans une barre d'outils

Il y a un petit subtil à gérer. Par défaut, une barre d'outils (JToolBar) affiche le texte de chaque action, ce qui n'est pas habituelle. Le texte de l'action doit être définit pour que l'on puisse l'afficher dans une barre de menu ou un menu contextuel, mail il faut demander à ne pas l'afficher pour une barre d'outils. Cela se fait grâce à la méthode setHideActionText. De style de codage peuvent être employés. Voici un premier style de codage, que je qualifierais de décomposé, consiste à récupérer un pointeur sur le bouton de la barre de menu dans une variable, puis d'utiliser ensuite cette variable pour invoquer la méthode setHideActionText.

 1 
 2 
 3 
JButton btnNew = toolBar.add( actNew );
btnNew.setHideActionText( true );
/* ... do other calls on btnNew */
Comment cacher le texte de l'action dans une barre d'outils - Style 1

Cette première technique vous permettra d'invoquer d'autres méthodes sur le bouton, si cela est nécessaire. La seconde technique est pratique si vous n'avez rien d'autre à demander au bouton : dans ce cas, il est inutile de produire une déclaration d'une variable pour un unique appel sur votre bouton. Voila comment procéder.

 1 
toolBar.add( actNew ).setHideActionText( true );
Comment cacher le texte de l'action dans une barre d'outils - Style 2

L'exemple de code complet

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
 97 
 98 
 99 
 100 
 101 
 102 
 103 
 104 
 105 
 106 
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 
 115 
 116 
 117 
 118 
 119 
 120 
 121 
 122 
 123 
 124 
 125 
 126 
 127 
 128 
 129 
 130 
 131 
 132 
 133 
 134 
 135 
 136 
 137 
 138 
 139 
 140 
 141 
 142 
 143 
 144 
 145 
 146 
 147 
 148 
 149 
 150 
 151 
 152 
 153 
 154 
 155 
 156 
 157 
 158 
 159 
 160 
 161 
 162 
 163 
 164 
 165 
 166 
 167 
 168 
 169 
 170 
 171 
 172 
 173 
 174 
 175 
 176 
 177 
 178 
 179 
 180 
 181 
 182 
 183 
 184 
 185 
 186 
 187 
 188 
 189 
 190 
 191 
 192 
 193 
 194 
 195 
 196 
 197 
 198 
 199 
 200 
 201 
 202 
 203 
 204 
 205 
 206 
 207 
 208 
 209 
 210 
 211 
 212 
 213 
 214 
 215 
 216 
 217 
 218 
 219 
 220 
 221 
 222 
 223 
 224 
 225 
 226 
 227 
 228 
 229 
 230 
 231 
 232 
 233 
 234 
 235 
 236 
 237 
 238 
 239 
 240 
 241 
 242 
 243 
 244 
 245 
 246 
 247 
 248 
 249 
 250 
 251 
 252 
 253 
 254 
 255 
 256 
 257 
 258 
 259 
 260 
 261 
 262 
 263 
 264 
 265 
 266 
 267 
 268 
 269 
 270 
 271 
 272 
 273 
 274 
 275 
 276 
 277 
 278 
 279 
 280 
 281 
 282 
 283 
 284 
 285 
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;


@SuppressWarnings( "serial" )
public class ActionSample extends JFrame {
    
   
    /* Construction de l'interface graphique */
    public ActionSample() {
        super( "Swing Action sample" );
        this.setSize(600,400);
        this.setLocationRelativeTo( null );
        this.setDefaultCloseOperation( DISPOSE_ON_CLOSE );
        
        // Construction et injection de la barre de menu
        this.setJMenuBar( this.createMenuBar() );

        // Construction et injection de la barre d'outils
        JPanel contentPane = (JPanel) getContentPane();
        contentPane.add( this.createToolBar(), BorderLayout.NORTH );

        // The content of the window
        JScrollPane leftScrollPane = new JScrollPane( new JTree() );
        leftScrollPane.setPreferredSize( new Dimension( 200, 0 ) );
        
        JTextArea textArea = new JTextArea();
        JScrollPane rightScrollPane = new JScrollPane( textArea );
        
        JSplitPane splitPane = new JSplitPane(
                JSplitPane.HORIZONTAL_SPLIT, leftScrollPane, rightScrollPane );
        contentPane.add( splitPane /*, BorderLayout.CENTER */ );    

        // Association d'un popup menu sur la zone d'édition de texte
        
        // Attention avant Java SE 8.0, il faut un final au début de la déclaration !!!
        JPopupMenu popupMenu = this.createPopupMenu();      
        textArea.addMouseListener( new MouseAdapter() {
            @Override public void mousePressed( MouseEvent event ) {
                if ( event.isPopupTrigger() ) {
                    popupMenu.show( event.getComponent(), event.getX(), event.getY() );
                }
            }
        } );    
    }
    
    
    /* Methode de construction de la barre de menu */
    private JMenuBar createMenuBar() {

        // La barre de menu à proprement parler
        JMenuBar menuBar = new JMenuBar();

        // Définition du menu déroulant "File" et de son contenu
        JMenu mnuFile = new JMenu( "File" );
        mnuFile.setMnemonic( 'F' );

        /*JMenuItem mnuNewFile =*/ mnuFile.add( actNew );
        mnuFile.addSeparator();
        mnuFile.add( actOpen );
        mnuFile.add( actSave );
        mnuFile.add( actSaveAs );
        mnuFile.addSeparator();
        mnuFile.add( actExit );
        
        menuBar.add(mnuFile);
        
        // Définition du menu déroulant "Edit" et de son contenu
        JMenu mnuEdit = new JMenu( "Edit" );
        mnuEdit.setMnemonic( 'E' );
        
        mnuEdit.add( actUndo );
        mnuEdit.add( actRedo );
        mnuEdit.addSeparator();
        mnuEdit.add( actCopy );
        mnuEdit.add( actCut );
        mnuEdit.add( actPaste );

        menuBar.add(mnuEdit);

        // Définition du menu déroulant "Help" et de son contenu
        JMenu mnuHelp = new JMenu( "Help" );
        mnuHelp.setMnemonic( 'H' );
        
        menuBar.add( mnuHelp );
        
        return menuBar;
    }

    /* Methode de construction de la barre d'outils */
    private JToolBar createToolBar() {
        JToolBar toolBar = new JToolBar();

        toolBar.add( actNew ).setHideActionText( true );
        toolBar.addSeparator();
        toolBar.add( actOpen ).setHideActionText( true );
        toolBar.add( actSave ).setHideActionText( true );
        toolBar.add( actSaveAs ).setHideActionText( true );
        toolBar.addSeparator();
        toolBar.add( actExit ).setHideActionText( true );
           
        return toolBar;
    }

    /* Methode de construction du menu contextuel */
    private JPopupMenu createPopupMenu() {
        JPopupMenu popupMenu = new JPopupMenu();
        
        popupMenu.add( actUndo );
        popupMenu.add( actRedo );
        popupMenu.addSeparator();
        popupMenu.add( actCopy );
        popupMenu.add( actCut );
        popupMenu.add( actPaste );

        return popupMenu;
    }

    /* Nos diverses actions */
    private AbstractAction actNew = new AbstractAction() {  
        {
            putValue( Action.NAME, "New File..." );
            putValue( Action.SMALL_ICON, new ImageIcon( "icons/new.png" ) );
            putValue( Action.MNEMONIC_KEY, KeyEvent.VK_N );
            putValue( Action.SHORT_DESCRIPTION, "New file (CTRL+N)" );
            putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK ) ); 
        }
        
        @Override public void actionPerformed( ActionEvent e ) {
            System.out.println( "New" );
        }
    };

    private AbstractAction actOpen = new AbstractAction() {  
        {
            putValue( Action.NAME, "Open File..." );
            putValue( Action.SMALL_ICON, new ImageIcon( "icons/open.png" ) );
            putValue( Action.MNEMONIC_KEY, KeyEvent.VK_O );
            putValue( Action.SHORT_DESCRIPTION, "Open file (CTRL+O)" );
            putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK ) ); 
        }
        
        @Override public void actionPerformed( ActionEvent e ) {
            System.out.println( "Open" );
        }
    };

    private AbstractAction actSave = new AbstractAction() {  
        {
            putValue( Action.NAME, "Save File" );
            putValue( Action.SMALL_ICON, new ImageIcon( "icons/save.png" ) );
            putValue( Action.MNEMONIC_KEY, KeyEvent.VK_S );
            putValue( Action.SHORT_DESCRIPTION, "Save file (CTRL+S)" );
            putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK ) ); 
        }
        
        @Override public void actionPerformed( ActionEvent e ) {
            System.out.println( "Save" );
        }
    };
   
    private AbstractAction actSaveAs = new AbstractAction() {  
        {
            putValue( Action.NAME, "Save As..." );
            putValue( Action.SMALL_ICON, new ImageIcon( "icons/save_as.png" ) );
            putValue( Action.MNEMONIC_KEY, KeyEvent.VK_A );
            putValue( Action.SHORT_DESCRIPTION, "Save file" );
        }
        
        @Override public void actionPerformed( ActionEvent e ) {
            System.out.println( "Save as" );
        }
    };
   
    private AbstractAction actExit = new AbstractAction() {  
        {
            putValue( Action.NAME, "Exit" );
            putValue( Action.SMALL_ICON, new ImageIcon( "icons/exit.png" ) );
            putValue( Action.MNEMONIC_KEY, KeyEvent.VK_X );
            putValue( Action.SHORT_DESCRIPTION, "Exit (ALT+F4)" );
            putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F4, KeyEvent.ALT_DOWN_MASK ) ); 
        }
        
        @Override public void actionPerformed( ActionEvent e ) {
            System.out.println( "Exit" );
        }
    };

    private AbstractAction actUndo = new AbstractAction() {  
        {
            putValue( Action.NAME, "Undo" );
            putValue( Action.SMALL_ICON, new ImageIcon( "icons/undo.png" ) );
            putValue( Action.MNEMONIC_KEY, KeyEvent.VK_U );
            putValue( Action.SHORT_DESCRIPTION, "Undo (CTRL+Z)" );
            putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.CTRL_DOWN_MASK ) ); 
        }
        
        @Override public void actionPerformed( ActionEvent e ) {
            System.out.println( "Undo" );
        }
    };

    private AbstractAction actRedo = new AbstractAction() {  
        {
            putValue( Action.NAME, "Redo" );
            putValue( Action.SMALL_ICON, new ImageIcon( "icons/redo.png" ) );
            putValue( Action.MNEMONIC_KEY, KeyEvent.VK_R );
            putValue( Action.SHORT_DESCRIPTION, "Redo (CTRL+U)" );
            putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK ) ); 
        }
        
        @Override public void actionPerformed( ActionEvent e ) {
            System.out.println( "Redo" );
        }
    };

    private AbstractAction actCopy = new AbstractAction() {  
        {
            putValue( Action.NAME, "Copy" );
            putValue( Action.SMALL_ICON, new ImageIcon( "icons/copy.png" ) );
            putValue( Action.MNEMONIC_KEY, KeyEvent.VK_C );
            putValue( Action.SHORT_DESCRIPTION, "Copy (CTRL+C)" );
            putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK ) ); 
        }
        
        @Override public void actionPerformed( ActionEvent e ) {
            System.out.println( "Copy" );
        }
    };

    private AbstractAction actCut = new AbstractAction() {  
        {
            putValue( Action.NAME, "Cut" );
            putValue( Action.SMALL_ICON, new ImageIcon( "icons/cut.png" ) );
            putValue( Action.MNEMONIC_KEY, KeyEvent.VK_T );
            putValue( Action.SHORT_DESCRIPTION, "Cut (CTRL+X)" );
            putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_DOWN_MASK ) ); 
        }
        
        @Override public void actionPerformed( ActionEvent e ) {
            System.out.println( "Cut" );
        }
    };

    private AbstractAction actPaste = new AbstractAction() {  
        {
            putValue( Action.NAME, "Paste" );
            putValue( Action.SMALL_ICON, new ImageIcon( "icons/paste.png" ) );
            putValue( Action.MNEMONIC_KEY, KeyEvent.VK_P );
            putValue( Action.SHORT_DESCRIPTION, "Paste (CTRL+V)" );
            putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK ) ); 
        }
        
        @Override public void actionPerformed( ActionEvent e ) {
            System.out.println( "Paste" );
        }
    };

    public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel( new NimbusLookAndFeel() );
        ActionSample frame = new ActionSample();
        frame.setVisible(true);
    }
}
Exemple d'utilisation d'action Swing


Mise en oeuvre d'un menu contextuel Utilisation de JRadioButton