4

假设我想在 Java 中制作一个按钮,这样当您单击它时,就会出现一个JPopupMenu。它出现的相关代码是menu.show(button, button.getWidth()/2, button.getHeight()/2);,它使JPopupMenu 以左上角在按钮的中心显示,如下图:

Current Swing JPopupMenu

但是,我希望它让左下角位于按钮的中心,有点像 iTunes 所做的(左下角下方有一个按钮,与左侧+按钮的大小相同其中):

在此处输入图像描述

我试图通过获取 JPopupMenu 的高度并将其添加到显示弹出菜单的 y 坐标来实现这一点,但我发现 JPopupMenu 在可见之前的高度为 0,这并不帮助我,因为我试图告诉计算机在哪里使它可见。此外,不可能在偏移量中进行硬编码,因为弹出窗口中的项目数不一定相同。

我怎样才能使我的高度未知的 JPopupMenu 可以显示,以便它的左下角坐标与给定坐标匹配?

4

3 回答 3

7

基本上,这会创建一个弹出菜单并使用JComponent#setComponentPopupMenu. 这意味着我不再需要监视鼠标事件或决定何时显示弹出窗口。

然后我覆盖JComponent#getPopupLocation并计算我希望弹出窗口出现的位置。

基本上,我得到JComponent#getComponentPopupMenu,得到它的首选大小并计算适当的偏移量,以便左下角现在出现在组件的中心......

在此处输入图像描述

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

    }
}

使用 Mac 输出更新

在此处输入图像描述

按钮示例

您不太可能找到完全满足您需求的解决方案。任何开发人员可以开发的最伟大的技能之一就是能够接受一个想法并在需要的地方塑造它。

前面的示例包含您需要的所有内容,您只需要能够从概念到解决方案的飞跃。

getPopupLocation是组件弹出 API 的一部分,因此覆盖该方法或调用它可能不是您所需要的(除非您有一个专门的任务按钮,这可能不是一件坏事),所以您需要适应满足您需求的解决方案...

在此处输入图像描述

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);
        }
    }
}
于 2013-05-10T05:42:17.603 回答
0

这实际上比我想象的要容易得多,并且在大多数情况下应该可以工作。我使用了你的 pastebin 代码并玩了一下。在你打电话setVisible(true)给框架后,我就可以打电话了menu.getPreferredSize()。只是将它打印到标准输出给了我java.awt.Dimension[width=31,height=62]。这可以在调用 ActionListener 之前完成,这样您就可以使用高度。

如果您在菜单中使用边框,则可能必须考虑到这一点,但上述方法应该有效。

于 2013-05-10T05:05:41.427 回答
0

这个答案只是为了备份我关于弹出可见性和 getPreferredSize() 的评论。

请注意,您可以获得零首选高度的弹出...如果它有零菜单项,那将是一个合乎逻辑的结论。

同样,应该接受 MadProgrammer 的回答。

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

PS:我通常不会恢复长期死的问题,但这次我正在寻找类似的东西,这是第一次在谷歌中找到。

于 2014-03-07T09:00:58.757 回答