Java Swing에서 오른쪽 클릭 컨텍스트 메뉴를 어떻게 생성합니까?


110

현재 마우스 오른쪽 버튼을 클릭 할 때 새 항목을 인스턴스화하고 JMenu해당 위치를 마우스 위치로 설정하여 오른쪽 클릭 컨텍스트 메뉴를 만들고 있습니다. 더 좋은 방법이 있습니까?

답변:


140

setVisible(true)메뉴를 수동으로 호출 하고 있을 것입니다 . 이로 인해 메뉴에서 불쾌한 버그가 발생할 수 있습니다.

show(Component, int x, int x)메서드는 필요한 모든 작업을 처리합니다 (마우스 오버시 항목을 강조 표시하고 필요한 경우 팝업 닫기). using 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()메서드를 사용해보십시오 .


위 코드를 사용한 후 "Figure 유형의 addMouseListener (MouseListener) 메서드는 인수 (PopClickListener)에 적용 할 수 없습니다."라는 오류 메시지가 표시됩니다. 감사합니다. Vinay

1
@ user1035905 PopClickListener확장 을 확인 했습니까 MouseAdapter?
jjnguy 2011

키보드의 컨텍스트 메뉴 키와 함께 작동하도록하려면 어떻게합니까?
Christoffer Hammarström

이 솔루션이 kleopatra의 솔루션보다 나은 유일한 경우는 사용자 정의 로직이 필요한 경우입니다 (예 : 다른 조건에서 다른 팝업 메뉴). 여전히, 당신은 상황에 맞는 메뉴 키 작업에 키보드 리스너를 추가해야

2
무엇 component을 의미합니까?
Loint

117

이 질문은 약간 오래되었습니다-답변과 튜토리얼도 마찬가지입니다.

Swing에서 popupMenu를 설정하는 현재 API는 다음과 같습니다.

myComponent.setComponentPopupMenu(myPopupMenu);

이렇게하면 마우스 및 키보드 트리거 모두에 대해 자동으로 표시됩니다 (후자는 LAF에 따라 다름). 또한 컨테이너의 자식간에 동일한 팝업을 재사용 할 수 있습니다. 해당 기능을 활성화하려면 :

myChild.setInheritsPopupMenu(true);

2
:-) IMO, 단순히 API를 문서를 읽고, 그것을 필요 아니에요 - @ user681159은 몰라
클레오 파트라

2
JTable선택한 행이나 마우스 오른쪽 버튼을 클릭 한 행에 표시되도록 어떻게 사용 하시겠습니까? 아니면이 시나리오에서 이전 방법을 선택해야합니까?
Alex Burdusel

1
@Burfee 중 하나를 서브 클래스로의 JTable을 강화하는 것이 나 : 재정의 getPopupLocation (..)을하고 나중에 사용의 위치를 저장, 최근 QA 참조 모든 SwingX 수집 구성 요소로 구현
클레오 파트라

18

클래스 사용 방법을 설명하는 The Java TutorialsHow to Use Menus 기사 에 Bringing Up a Popup Menu 에 대한 섹션이 있습니다 .JPopupMenu

튜토리얼의 예제 코드 MouseListener는 팝업 메뉴를 표시해야하는 구성 요소에 를 추가 하고 그에 따라 메뉴를 표시하는 방법을 보여줍니다 .

(설명하는 방법은 튜토리얼이 구성 요소에 팝업 메뉴를 표시하는 방법을 제시하는 방법과 상당히 유사합니다.)


8

다음 코드 Windows는 복사, 잘라 내기, 붙여 넣기, 모두 선택, 실행 취소 및 다시 실행 기능으로 알려진 기본 컨텍스트 메뉴를 구현 합니다. 또한 작동 LinuxMac 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마우스 오른쪽 버튼을 클릭하면 컨텍스트 메뉴가 나타납니다.


훌륭한 솔루션입니다. 한 가지 : 모든 플랫폼에서 제대로 작동 하는 releasedEvent.isPopupTrigger()대신 사용할 수 / 있어야합니다 releasedEvent.getButton() == MouseEvent.BUTTON3.
Frederic Leitenberger

key-listener의 또 하나의 버그 : pressedEvent.getModifiersEx() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()둘 중 하나 Ex이거나 아니 어야합니다 Ex. 의 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.