Java Swingで右クリックコンテキストメニューを作成するにはどうすればよいですか?


110

現在、右クリックで新しいインスタンスを作成し、JMenuその位置をマウスの位置に設定することで、右クリックのコンテキストメニューを作成しています...より良い方法はありますか?

回答:


140

おそらく手動でsetVisible(true)メニューを呼び出しています。これにより、メニューに厄介なバグが発生する可能性があります。

このshow(Component, int x, int x)メソッドは、発生する必要のあるすべてのことを処理します(マウスオーバーで強調表示し、必要に応じてポップアップを閉じる)。使用setVisible(true)すると、追加の動作を追加せずにメニューが表示されます。

右クリックポップアップメニューを作成するには、単にを作成しJPopupMenuます。

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

次に、MouseListenerメニューをポップアップするコンポーネントにカスタムを追加するだけです。

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());

もちろん、チュートリアルにはもう少し詳細な説明があります。

注:ポップアップメニューが、ユーザーがクリックした場所から離れたところに表示されていることに気付いた場合は、x座標とy座標のe.getXOnScreen()およびe.getYOnScreen()メソッドを使用してみてください。


上記のコードを使用した後、私はよろしく、ビナイ「タイプ図でメソッドaddMouseListener(MouseListenerインタフェース)は引数(PopClickListener)には適用されません」というエラーを取得

1
@ user1035905 PopClickListener拡張することを確認しましたMouseAdapterか?
jjnguy

キーボードのコンテキストメニューキーを使用するにはどうすればよいですか。
ChristofferHammarström12年

このソリューションがkleopatraのソリューションよりも優れている唯一のケースは、カスタムロジックを実行する必要がある場合です(たとえば、異なる条件下で異なるポップアップメニュー)。それでも、コンテキストメニューキーを操作するにはキーボードリスナーを追加する必要があります

2
何のcomponent略ですか?
Loint 2016年

117

この質問は少し古いです-答えも(そしてチュートリアルも)

SwingでpopupMenuを設定するための現在のAPIは次のとおりです。

myComponent.setComponentPopupMenu(myPopupMenu);

このようにして、マウスとキーボードの両方のトリガーに対して後者が自動的に表示されます(後者はLAFに依存します)。さらに、コンテナの子全体で同じポップアップを再利用することもできます。その機能を有効にするには:

myChild.setInheritsPopupMenu(true);

2
@ user681159は何も知りません-そしてそれは必要ありません、IMO、単にapi docを読んでください:-)
kleopatra

2
JTable選択した行または右クリックした行にポップするように、これをどのように使用しますか?または、このシナリオでは、古い方法が選択される方法ですか?
Alex Burdusel 2013

1
@Burfeeまたはサブクラス化によってJTableを拡張:getPopupLocation(..)をオーバーライドし、後で使用するために場所を保存します。すべてのSwingXコレクションコンポーネントに実装されている最新のQA参照してください
kleopatra

18

上のセクションがありますポップアップメニューの始動どのように使用するためにメニューのの記事ザ・Javaのチュートリアルを使用する方法について説明JPopupMenuクラスが。

チュートリアルのサンプルコードは、MouseListenerポップアップメニューを表示するコンポーネントにを追加し、それに応じてメニューを表示する方法を示しています。

(説明する方法は、コンポーネントにポップアップメニューを表示する方法をチュートリアルが提示する方法とかなり似ています。)


8

次のコードはWindows、コピー、切り取り、貼り付け、すべて選択、元に戻す、やり直し機能を備えたデフォルトのコンテキストメニューを実装しています。また、上で動作Linuxして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);
    }
}

使用法:

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

これで、textArea右クリックするとコンテキストメニューが表示されます。


素晴らしいソリューション。1つのこと:すべてのプラットフォームで正しく動作するためreleasedEvent.isPopupTrigger()に、代わりにreleasedEvent.getButton() == MouseEvent.BUTTON3を使用することができます/使用する必要があります。
フレデリックライテンベルガー

キーリスナーにおけるもう一つのバグ:pressedEvent.getModifiersEx() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()これらは両方のどちらかでなければなりませんExEx。のExバージョンはgetMenuShortcutKeyMask()、Java 10以降でのみ使用できます。
Frederic Leitenberger

1

@BullyWillPlazaが提案したそのメソッドの使用法を修正します。理由は、contextMenuのみにtextAreaを追加しようとすると表示されないためです。contextMenuと一部のパネルの両方に追加すると、次のようになります。デザインエディターに切り替えようとすると、親の二重関連付けが異なります。

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

ポップアップが必要なテキストオブジェクトに対して、このようなマウスリスナーを作成します。これにより、テキストオブジェクトを右クリックすると、ポップアップが追加されて表示されます。これにより、エラーが発生しなくなります。@BullyWillPlazaが作成したソリューションは、プログラムに実装するのに非常に優れており、リッチで高速です。


また、そのcontextMenuをインポートして新しいインスタンスを作成する必要があることも忘れないでください。
Đumićブラニスラフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.