Make JPopupMenu Display with a Certain Bottom Left Coordinate

后端 未结 3 702
谎友^
谎友^ 2020-12-11 21:07

Say that I want to make a button in Java in such a way so that when you click on it, a JPopupMenu appears. The relevant code for it appearing is menu.show(button, butt

相关标签:
3条回答
  • 2020-12-11 21:45

    Basically, this creates a popup menu and registers it with the component using JComponent#setComponentPopupMenu. This means that I no longer need to monitor for mouse events or make decisions about when to show the popup.

    I then override JComponent#getPopupLocation and calculate the location where I want the popup to appear.

    Basically, I get the JComponent#getComponentPopupMenu, get it's preferred size and calculate an appropriate offset so that the bottom, left corner now appears in the center of the component...

    enter image description here

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Point;
    import java.awt.event.MouseEvent;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JMenuItem;
    import javax.swing.JPanel;
    import javax.swing.JPopupMenu;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class TestPopup02 {
    
        public static void main(String[] args) {
            new TestPopup02();
        }
    
        public TestPopup02() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            public TestPane() {
                JPopupMenu menu = new JPopupMenu();
                menu.add(new JMenuItem("Edit Playlist"));
                menu.addSeparator();
                menu.add(new JMenuItem("Check for Available Downloads..."));
                menu.addSeparator();
                menu.add(new JMenuItem("Export..."));
                menu.add(new JMenuItem("Burn Playlist to Disc"));
                menu.add(new JMenuItem("Copy To Play Order"));
                menu.addSeparator();
                menu.add(new JMenuItem("Delete"));
                setComponentPopupMenu(menu);
            }
    
            @Override
            public Point getPopupLocation(MouseEvent event) {
                // Get the registered popup menu...
                JPopupMenu popup = getComponentPopupMenu();
                // Get the super point, just in case...
                Point pos = super.getPopupLocation(event);
                if (popup != null) {
                    // Create a new "point" location
                    pos = new Point();
                    // get the preferred size of the menu...
                    Dimension size = popup.getPreferredSize();
                    // Adjust the x position so that the left side of the popup
                    // appears at the center of  the component
                    pos.x = (getWidth() / 2);
                    // Adjust the y position so that the y postion (top corner)
                    // is positioned so that the bottom of the popup
                    // appears in the center
                    pos.y = (getHeight() / 2) - size.height;
                }
                return pos;
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                // Simply draws a cross in the center of the window, so you 
                // know where the center is...
                int width = getWidth() - 1;
                int height = getHeight() - 1;
                g.drawLine(width / 2, 0, width / 2, height);
                g.drawLine(0, height / 2, width, height / 2);
            }
    
        }
    }
    

    Update with Mac output

    enter image description here

    Button example

    It is unlikely that you will ever find a solution that meets precisely your needs. One of the greatest skills any developer can develop is the ability to take an idea and mold it there needs.

    The previous example holds every thing you need, you just need to be able to make the leap from concept to solution.

    getPopupLocation is part of the component popup API, so either overriding the method or calling it probably isn't quite what you need (unless you have a dedicated button for the task, which may not be a bad thing), so you would need to adapt the solution to your needs...

    enter image description here

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.GridBagLayout;
    import java.awt.Point;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseEvent;
    import javax.swing.JButton;
    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 TestPopup02 {
    
        public static void main(String[] args) {
            new TestPopup02();
        }
    
        public TestPopup02() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private JButton button;
            private JPopupMenu popup;
    
            public TestPane() {
                popup = new JPopupMenu();
                popup.add(new JMenuItem("Edit Playlist"));
                popup.addSeparator();
                popup.add(new JMenuItem("Check for Available Downloads..."));
                popup.addSeparator();
                popup.add(new JMenuItem("Export..."));
                popup.add(new JMenuItem("Burn Playlist to Disc"));
                popup.add(new JMenuItem("Copy To Play Order"));
                popup.addSeparator();
                popup.add(new JMenuItem("Delete"));
    
                setLayout(new GridBagLayout());
                button = new JButton("+");
                button.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        popup.pack();
                        Point pos = new Point();
                        // get the preferred size of the menu...
                        Dimension size = popup.getPreferredSize();
                        // Adjust the x position so that the left side of the popup
                        // appears at the center of  the component
                        pos.x = (button.getWidth() / 2);
                        // Adjust the y position so that the y postion (top corner)
                        // is positioned so that the bottom of the popup
                        // appears in the center
                        pos.y = (button.getHeight() / 2) - size.height;
                        popup.show(button, pos.x, pos.y);
                    }
                });
                add(button);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                // Simply draws a cross in the center of the window, so you 
                // know where the center is...
                int width = getWidth() - 1;
                int height = getHeight() - 1;
                g.drawLine(width / 2, 0, width / 2, height);
                g.drawLine(0, height / 2, width, height / 2);
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-11 22:02

    This is actually much easier than I thought and should work in most cases. I used your pastebin code and played around it a bit. After you call setVisible(true) on the frame I was able to call menu.getPreferredSize(). Just printing it to standard out gave me java.awt.Dimension[width=31,height=62]. This can be done prior to your ActionListener is called so you will be able to make use of height.

    If you use a border in your menu you might have to take this into account but the above should work.

    0 讨论(0)
  • 2020-12-11 22:03

    This answer just serves to backup my comment about popup visibility and getPreferredSize().

    Note that you COULD get a zero preferred height for a popup...if it has zero menu items, that would be a logical conclusion.

    Again, MadProgrammer's answer should be accepted.

    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JMenuItem;
    import javax.swing.JPopupMenu;
    import javax.swing.SwingUtilities;
    
    public class ButtonPopup extends JFrame {
    
        private JButton button;
    
        public ButtonPopup() {        
            setLayout(new GridBagLayout());
    
            button = new JButton("Click Meh~ /o/");
            button.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    JPopupMenu popup = new JPopupMenu();
                    popup.add(new JMenuItem("A"));
                    popup.add(new JMenuItem("B"));
                    popup.add(new JMenuItem("C"));
    
                    // you want this
                    int height = popup.getPreferredSize().height;
                    popup.show(
                            button, button.getWidth() / 2,
                            -height + (button.getHeight() / 2));
                }
            });
    
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.insets = new Insets(5, 5, 5, 5);
            add(button, gbc);
    
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            pack();
    
            setLocationRelativeTo(null);
        }
    
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
    
                public void run() {
                    new ButtonPopup().setVisible(true);
                }
            });
        }
    }
    

    P.S.: I don't usually revive long dead questions, but this time I was looking for something similar an this was to first hit in google.

    0 讨论(0)
提交回复
热议问题