web-dev-qa-db-fra.com

Comment créer un menu contextuel avec le clic droit dans Java Swing?

Je crée actuellement un menu contextuel par clic droit en instanciant un nouveau JMenu sur un clic droit et en définissant son emplacement sur celui de la souris ... Existe-t-il un meilleur moyen?

108
Wayne

Vous appelez probablement manuellement setVisible(true) dans le menu. Cela peut entraîner des problèmes de comportement dans le menu.

La méthode show(Component, int x, int x) gère tout ce dont vous avez besoin (Mise en surbrillance au passage de la souris et fermeture de la fenêtre contextuelle si nécessaire). Utiliser setVisible(true) montre simplement le menu sans ajouter de comportement supplémentaire.

Pour créer un menu contextuel avec un clic droit, créez simplement un JPopupMenu .

class PopUpDemo extends JPopupMenu {
    JMenuItem anItem;
    public PopUpDemo() {
        anItem = new JMenuItem("Click Me!");
        add(anItem);
    }
}

Ensuite, tout ce que vous avez à faire est d’ajouter un composant personnalisé MouseListener aux composants pour lesquels vous souhaitez que le menu apparaisse.

class PopClickListener extends MouseAdapter {
    public void mousePressed(MouseEvent e) {
        if (e.isPopupTrigger())
            doPop(e);
    }

    public void mouseReleased(MouseEvent e) {
        if (e.isPopupTrigger())
            doPop(e);
    }

    private void doPop(MouseEvent e) {
        PopUpDemo menu = new PopUpDemo();
        menu.show(e.getComponent(), e.getX(), e.getY());
    }
}

// Then on your component(s)
component.addMouseListener(new PopClickListener());

Bien sûr, les tutoriels ont une explication légèrement plus en profondeur .

Remarque: Si vous remarquez que le menu contextuel apparaît très loin de l'endroit où l'utilisateur a cliqué, essayez d'utiliser les fonctions e.getXOnScreen() et e.getYOnScreen() méthodes pour les coordonnées x et y.

138
jjnguy

Cette question est un peu ancienne - de même que les réponses (et le tutoriel également)

L’API actuelle pour configurer un menu contextuel dans Swing est

myComponent.setComponentPopupMenu(myPopupMenu);

De cette façon, il sera montré automatiquement, tant pour les déclencheurs de souris que de clavier (ce dernier dépend de LAF). De plus, il prend en charge la réutilisation de la même fenêtre contextuelle sur les enfants d'un conteneur. Pour activer cette fonctionnalité:

myChild.setInheritsPopupMenu(true);
113
kleopatra

Il y a une section sur Créer un menu contextuel dans le Comment utiliser les menus Article de Le Java Tutorials ce qui explique comment utiliser la classe JPopupMenu .

L'exemple de code du tutoriel montre comment ajouter MouseListeners aux composants devant afficher un menu contextuel, et l'affiche en conséquence.

(La méthode que vous décrivez est assez similaire à la façon dont le didacticiel présente la manière d'afficher un menu contextuel sur un composant.)

18
coobird

Le code suivant implémente un menu contextuel par défaut connu de Windows avec des fonctions copier, couper, coller, tout sélectionner, annuler et rétablir. Cela fonctionne aussi sur Linux et Mac OS X:

import javax.swing.*;
import javax.swing.text.JTextComponent;
import javax.swing.undo.UndoManager;
import Java.awt.*;
import Java.awt.datatransfer.Clipboard;
import Java.awt.datatransfer.DataFlavor;
import Java.awt.event.KeyAdapter;
import Java.awt.event.KeyEvent;
import Java.awt.event.MouseAdapter;
import Java.awt.event.MouseEvent;

public class DefaultContextMenu extends JPopupMenu
{
    private Clipboard clipboard;

    private UndoManager undoManager;

    private JMenuItem undo;
    private JMenuItem redo;
    private JMenuItem cut;
    private JMenuItem copy;
    private JMenuItem paste;
    private JMenuItem delete;
    private JMenuItem selectAll;

    private JTextComponent textComponent;

    public DefaultContextMenu()
    {
        undoManager = new UndoManager();
        clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();

        addPopupMenuItems();
    }

    private void addPopupMenuItems()
    {
        undo = new JMenuItem("Undo");
        undo.setEnabled(false);
        undo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        undo.addActionListener(event -> undoManager.undo());
        add(undo);

        redo = new JMenuItem("Redo");
        redo.setEnabled(false);
        redo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        redo.addActionListener(event -> undoManager.redo());
        add(redo);

        add(new JSeparator());

        cut = new JMenuItem("Cut");
        cut.setEnabled(false);
        cut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        cut.addActionListener(event -> textComponent.cut());
        add(cut);

        copy = new JMenuItem("Copy");
        copy.setEnabled(false);
        copy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        copy.addActionListener(event -> textComponent.copy());
        add(copy);

        paste = new JMenuItem("Paste");
        paste.setEnabled(false);
        paste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        paste.addActionListener(event -> textComponent.paste());
        add(paste);

        delete = new JMenuItem("Delete");
        delete.setEnabled(false);
        delete.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        delete.addActionListener(event -> textComponent.replaceSelection(""));
        add(delete);

        add(new JSeparator());

        selectAll = new JMenuItem("Select All");
        selectAll.setEnabled(false);
        selectAll.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        selectAll.addActionListener(event -> textComponent.selectAll());
        add(selectAll);
    }

    private void addTo(JTextComponent textComponent)
    {
        textComponent.addKeyListener(new KeyAdapter()
        {
            @Override
            public void keyPressed(KeyEvent pressedEvent)
            {
                if ((pressedEvent.getKeyCode() == KeyEvent.VK_Z)
                        && ((pressedEvent.getModifiersEx() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) != 0))
                {
                    if (undoManager.canUndo())
                    {
                        undoManager.undo();
                    }
                }

                if ((pressedEvent.getKeyCode() == KeyEvent.VK_Y)
                        && ((pressedEvent.getModifiersEx() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) != 0))
                {
                    if (undoManager.canRedo())
                    {
                        undoManager.redo();
                    }
                }
            }
        });

        textComponent.addMouseListener(new MouseAdapter()
        {
            @Override
            public void mousePressed(MouseEvent releasedEvent)
            {
                handleContextMenu(releasedEvent);
            }

            @Override
            public void mouseReleased(MouseEvent releasedEvent)
            {
                handleContextMenu(releasedEvent);
            }
        });

        textComponent.getDocument().addUndoableEditListener(event -> undoManager.addEdit(event.getEdit()));
    }

    private void handleContextMenu(MouseEvent releasedEvent)
    {
        if (releasedEvent.getButton() == MouseEvent.BUTTON3)
        {
            processClick(releasedEvent);
        }
    }

    private void processClick(MouseEvent event)
    {
        textComponent = (JTextComponent) event.getSource();
        textComponent.requestFocus();

        boolean enableUndo = undoManager.canUndo();
        boolean enableRedo = undoManager.canRedo();
        boolean enableCut = false;
        boolean enableCopy = false;
        boolean enablePaste = false;
        boolean enableDelete = false;
        boolean enableSelectAll = false;

        String selectedText = textComponent.getSelectedText();
        String text = textComponent.getText();

        if (text != null)
        {
            if (text.length() > 0)
            {
                enableSelectAll = true;
            }
        }

        if (selectedText != null)
        {
            if (selectedText.length() > 0)
            {
                enableCut = true;
                enableCopy = true;
                enableDelete = true;
            }
        }

        if (clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor) && textComponent.isEnabled())
        {
            enablePaste = true;
        }

        undo.setEnabled(enableUndo);
        redo.setEnabled(enableRedo);
        cut.setEnabled(enableCut);
        copy.setEnabled(enableCopy);
        paste.setEnabled(enablePaste);
        delete.setEnabled(enableDelete);
        selectAll.setEnabled(enableSelectAll);

        // Shows the popup menu
        show(textComponent, event.getX(), event.getY());
    }

    public static void addDefaultContextMenu(JTextComponent component)
    {
        DefaultContextMenu defaultContextMenu = new DefaultContextMenu();
        defaultContextMenu.addTo(component);
    }
}

Usage:

JTextArea textArea = new JTextArea();
DefaultContextMenu.addDefaultContextMenu(textArea);

Maintenant, le textArea aura un menu contextuel quand il sera cliqué avec le bouton droit.

6
BullyWiiPlaza

Je corrigerai l'utilisation de cette méthode suggérée par @BullyWillPlaza. La raison en est que lorsque j'essaie d'ajouter textArea à contextMenu uniquement, il n'est pas visible. Si je l'ajoute à la fois à contextMenu et à certains panneaux, il affiche une double association de parents si j'essaie de passer à l'éditeur de conception.

TexetObjcet.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            if (SwingUtilities.isRightMouseButton(e)){
                contextmenu.add(TexetObjcet);
                contextmenu.show(TexetObjcet, 0, 0);
            }
        }
    }); 

Faites ce type d’écouteur avec la souris pour l’objet texte sur lequel vous devez afficher une fenêtre contextuelle. Ce que cela va faire, c’est que lorsque vous cliquez avec le bouton droit de la souris sur votre objet texte, celui-ci sera ajouté et affiché. De cette façon, vous ne rencontrez pas cette erreur. La solution faite par @BullyWillPlaza est très bonne, riche et rapide à implémenter dans votre programme. Vous devriez donc l'essayer pour voir comment vous l'aimez.

1
Đumić Branislav