JPopupMenu not showing on the screen?

2019-09-05 21:26发布

问题:

So for my school project I am creating a Class Diagram maker. I am 95% done with it and all I need is to make the Jpopup menu appear. In the core I have 3 files. The ApplicationModel which extends the JFrame, ClassDiagram which extends the JPanel and ClassModel which makes the Rectangles (in the picture) appear. The core of the rendering is on Rectangle objects and the text inside the middle and bottom rectangles are surrounded by another invisible rectangle, which is right-clickable.

This is what the program looks like (Minus the paint editting) Now for the file that handles the clicking is DiagramMouseListener, here is the code for it.

package edu.mville.cs.classdiagram;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

public class DiagramMouseListener extends MouseAdapter
{
    ClassDiagram diagram;
    Field field;
    Method method;
    int x;
    int y;
    ClassModel elementBeingDragged;

    JPopupMenu fieldPopupMenu = new JPopupMenu();
    JPopupMenu methodPopupMenu = new JPopupMenu();

    JMenuItem editFieldNameItem;
    JMenuItem createFieldItem;
    JMenuItem deleteFieldItem;

    JMenuItem editMethodNameItem;
    JMenuItem createMethodItem;
    JMenuItem deleteMethodItem;

    public DiagramMouseListener(ClassDiagram diagram) { this.diagram = diagram; }

    public void addPopupMenu()
    {
        editFieldNameItem = new JMenuItem("Edit Field Name");
        createFieldItem = new JMenuItem("New Field");
        deleteFieldItem = new JMenuItem("Delete Field");

        editMethodNameItem = new JMenuItem("Edit Method Name");
        createMethodItem = new JMenuItem("New Method");
        deleteMethodItem = new JMenuItem("Delete Method");

        methodPopupMenu.add(editMethodNameItem);
        methodPopupMenu.add(createMethodItem);
        methodPopupMenu.add(deleteMethodItem);

        fieldPopupMenu.add(editFieldNameItem);
        fieldPopupMenu.add(createFieldItem);
        fieldPopupMenu.add(deleteFieldItem);

        editFieldNameItem.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent ae)
            {

            }
        });
        /*
        createFieldItem.addActionListener(this);
        deleteFieldItem.addActionListener(this);
        editMethodNameItem.addActionListener(this);
        createMethodItem.addActionListener(this);
        deleteMethodItem.addActionListener(this);
        */
    }

    @Override
    public void mouseClicked(MouseEvent me)
    {        
        if(SwingUtilities.isLeftMouseButton(me) && me.getClickCount() == 2)
        {
            diagram.doubleClick(me.getPoint());
        }
    }

    @Override
    public void mousePressed(MouseEvent e)
    {
        x = e.getX();
        y = e.getY();

        DiagramElement elt = diagram.containsPoint(e.getPoint());
        if (elt instanceof ClassModel)
        {
            elementBeingDragged = (ClassModel) elt;
        }
    }

    @Override
    public void mouseDragged(MouseEvent e)
    {
        int dx = e.getX() - x;
        int dy = e.getY() - y;

        if (elementBeingDragged != null)
        {
            elementBeingDragged.move(dx, dy);

            diagram.repaint();
        }

        x += dx;
        y += dy;
    }

    @Override
    public void mouseReleased(MouseEvent me)
    {
        elementBeingDragged = null;

        DiagramElement de = diagram.containsPoint(me.getPoint());

        if (SwingUtilities.isRightMouseButton(me) && me.getClickCount() == 1 && de instanceof Field)
        {
            if (me.isPopupTrigger())
            {
                System.out.println("it is");
                fieldPopupMenu.show(me.getComponent(), me.getX(), me.getY());
            }
        }
        else if (SwingUtilities.isRightMouseButton(me) && me.getClickCount() == 1 && de instanceof Method)
        {
            if (me.isPopupTrigger())
            {
                System.out.println("it is");
                methodPopupMenu.show(me.getComponent(), me.getX(), me.getY());
            }
        }  
    }
}

At line 118 where it says System.out.println("it is"); It successfully displays the text on console, which tells me the code successfully reached that part, but the popup menu is never displayed when I right click the text (which is inside invisible Rectangles separated by 5 pixels of space).

I tried multiple solutions to this problem. I even looked at the oracle tutorials and other user's examples to see what was wrong with my code. But after countless hours of searching, I failed to fix the problem. Any help would be appreciated. Also if you need more information, I will be glad to provide! Thanks.

回答1:

Several things;

First off, the popup coordinates should be relative to the component you are triggering the popup on, not the screen coordinates. What is happening is, the API is calculating the screen location of the component and adding the x/y values you pass, which is possibly pushing the popup off the screen

fieldPopupMenu.show(me.getComponent(), me.getX(), me.getY());

Secondly, popups can be triggered on different systems by different events. You should be checking for isPopupTrigger in mousePressed, mouseReleased and even mouseClicked.

Lastly, popups can be triggered by different mouse buttons (and even possibly other conditions), so should only need to check isPopupTrigger

Additionally, you could just use JComponent#setComponentPopupMenu

Updated with setComponentPopupMenu example

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class PopupMenuTest {

    public static void main(String[] args) {
        new PopupMenuTest();
    }

    public PopupMenuTest() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JPopupMenu popupMenu;

        public TestPane() {
            popupMenu = new JPopupMenu();
            popupMenu.add(new JMenuItem("Open..."));
            popupMenu.add(new JMenuItem("Save..."));
            popupMenu.add(new JMenuItem("Close..."));
            popupMenu.add(new JMenuItem("Give Blood..."));
            popupMenu.add(new JMenuItem("Give Money..."));

            setComponentPopupMenu(popupMenu);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

}

Updated with MouseListener example

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class PopupMenuTest {

    public static void main(String[] args) {
        new PopupMenuTest();
    }

    public PopupMenuTest() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JPopupMenu popupMenu;

        public TestPane() {
            popupMenu = new JPopupMenu();
            popupMenu.add(new JMenuItem("Open..."));
            popupMenu.add(new JMenuItem("Save..."));
            popupMenu.add(new JMenuItem("Close..."));
            popupMenu.add(new JMenuItem("Give Blood..."));
            popupMenu.add(new JMenuItem("Give Money..."));

            addMouseListener(new MouseAdapter() {

                protected void doPopup(MouseEvent evt) {
                    if (evt.isPopupTrigger()) {
                        popupMenu.show(evt.getComponent(), evt.getX(), evt.getY());
                    }
                }

                @Override
                public void mouseClicked(MouseEvent e) {
                    doPopup(e);
                }

                @Override
                public void mousePressed(MouseEvent e) {
                    doPopup(e);
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    doPopup(e);
                }

            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

}