java - 为什么 JLabel.getLocationOnScreen() 返回 diffirently 取决于父 JPanel 布局

标签 java swing layout jframe jlabel

我使用 Jave Swing,简化的层次结构可以理解为 JFrame -> JPanel -> JLabel。

现在我可以选择将 JLabel 添加到 JPanel 中:

  1. panel.add(label);
  2. panel.setLayout(new BorderLayout()); panel.add(label, BorderLayout.NORTH);

这是我在这两种情况下所做的常见配置

panel.setOpaque(false);
panel.setBorder(BorderFactory.createLineBorder(Color.yellow));

即使我保持所有其他代码不变,以下方法调用也会产生截然不同的结果:

    Point location = getLocationOnFrame(label);

我调用此方法来确定 JLabel 相对于 JFrame 的位置:

    public Point getLocationOnFrame (JLabel label) {
        if (label == null) return null;

        try {
            Point location = label.getLocationOnScreen();
            System.out.println(location);
            Point frameOffset = mainFrame.getLocationOnScreen();
            System.out.println(frameOffset);
            location.translate(-frameOffset.x, -frameOffset.y);
            return location;
        } catch (IllegalComponentStateException e) {}

        return null;
    }

这些是 System.out.println() 的结果,即使在视觉上标 checkout 现在同一个地方。

java.awt.Point[x=578,y=305]
java.awt.Point[x=0,y=0]

java.awt.Point[x=224,y=300]
java.awt.Point[x=0,y=0]

在我看来,在第二种情况下,数字来自父 JPanel 的左上角而不是 JLabel 本身。

基本上我正在尝试使用第二种情况的代码并从第一种情况中获取数字。

最佳答案

至于为什么你会得到不同的结果,我完全不知道。

但是,我相信您正在为自己做更多的工作...

Point loc = label.getLocation();
Window win = SwingUtilities.getWindowAncestor(label);
Point wrPos = SwingUtilities.convertPoint(label, loc, win);

将为您将标签坐标转换为窗口坐标空间。

请记住,框架的位置是框架的左上角(不,真的是 ;)),但您的标签存在于框架的 contentPane 内,它在框架内偏移边框,因此根据您尝试执行的操作,您最好使用 contentPane 而不是框架 ;)

这是我用来测试逻辑的一个简单示例;)

public class TestLocation {

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

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

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new LocationPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class LocationPane extends JPanel {

        private JLabel label;

        public LocationPane() {
            setLayout(new GridBagLayout());
            label = new JLabel("A Label");
            add(label);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            // While this works, really, don't do this, in paint methods
            // it's expensive and will slow down your system ;)
            Point loc = label.getLocation();
            Point pos = label.getLocationOnScreen();
            Window win = SwingUtilities.getWindowAncestor(this);
            Point wPos = win.getLocationOnScreen();
            Point wLoc = win.getLocation();

            Point rPos = SwingUtilities.convertPoint(label, label.getLocation(), win);
            JRootPane rootPane = SwingUtilities.getRootPane(this);
            Point cPos = SwingUtilities.convertPoint(label, loc, rootPane.getContentPane());
            Point wrPos = SwingUtilities.convertPoint(label, loc, win);

            FontMetrics fm = g2d.getFontMetrics();
            int rowHeight = fm.getHeight();

            String[] messages = new String[]{
                "Label.location = " + loc.x + "x" + loc.y,
//                "Label.locationOnScreen = " + pos.x + "x" + pos.y,
//                "Window.location = " + wLoc.x + "x" + wLoc.y,
//                "Window.locationOnScreen = " + wPos.x + "x" + wPos.y,
                "RelativeTo.Window = " + wrPos.x + "x" + wrPos.y,
                "RelativeTo.RootPane = " + rPos.x + "x" + rPos.y,
                "RelativeTo.ContentPane = " + cPos.x + "x" + cPos.y,
            };

            int y = 0;
            for (String msg : messages) {
                g2d.drawString(msg, 0, y + fm.getAscent());
                y += rowHeight;
            }

        }

    }

}

关于java - 为什么 JLabel.getLocationOnScreen() 返回 diffirently 取决于父 JPanel 布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13302440/

相关文章:

javascript - 将动态元素放在行上,占用所有可用空间,而不会跨多行打断组

java - Micronaut 与 MockitoTests

java - ORMLite 混合 orderBy() 和 orderByRaw()

java - 如何让按钮单击显示组合选项

Java 外观 (L&F)

java - MigLayout - 需要有关如何使用停靠参数的帮助(或需要替代方案)

Java : Convert from doc to pdf and ppt to pdf failing

java - Spring mvc 测试+mockito。 @ModelAttribute 空指针

java - 如何从单击按钮的代码中进行调用?

java - 如何为 GridBagLayout 中的所有组件设置间隙?