SwingUtilities.convertPoint() 返回负值

4

我在另一个复杂的JPanels结构和大量代码的项目中遇到了这个问题。

在那里,我有以下代码片段:

Point point = label.getLocation();
Point point2 = SwingUtilities.convertPoint(label.getParent(), point, panel);

在动态选择标签和面板的情况下,JLabel应该是JPanel的孙子辈。

那么问题就是:在源和目标具有子父关系的情况下,什么情况下SwingUtilities.convertPoint()会返回负值?这种情况可能吗?

以下代码演示了负坐标问题,但此时panel22不是label的父级元素。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

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

    public NegativeLocation() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());

                JPanel panel1 = new JPanel() {
                     @Override
                     public Dimension getPreferredSize() {
                         return new Dimension(600, 400);
                     }
                };

                JPanel panel21 = new JPanel() {
                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(300, 400);
                    }
                };
                panel1.add(panel21);

                JPanel panel22 = new JPanel() {
                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(300, 400);
                    }
                };
                panel1.add(panel22);

                JPanel panel3 = new JPanel() {
                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(300, 400);
                    }
                };
                panel21.add(panel3);

                JLabel label = new JLabel("Label");
                panel3.add(label);

                frame.getContentPane().add(panel1);
                frame.setPreferredSize(new Dimension(600, 400));

                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                Point point = label.getLocation();
                Point point2 = SwingUtilities.convertPoint(label.getParent(), point, panel21);
                Point point3 = SwingUtilities.convertPoint(label.getParent(), point, panel22);

                System.out.println(point2);
                System.out.println(point3);
            }
        });
    }
}

因此,输出结果为:
java.awt.Point[x=134,y=10]
java.awt.Point[x=134,y=-395]

更新:基本上,我需要获取label相对于panel21的位置。如何修改这行代码以实现它?

Point point = label.getLocation();
Point point2 = SwingUtilities.convertPoint(label.getParent(), point, panel21);

这是因为您传递了JLabel的位置,但传递了标签的父级,因此位置信息现在无效。 - MadProgrammer
@MadProgrammer 但是 getLocation() 返回相对于父级的结果。因此,我将父级指定为源。我的逻辑有什么问题吗? - Nikolay Kuznetsov
但是转换位置方法期望子项在其自身坐标空间中的位置,而不是父项的位置。 - MadProgrammer
@MadProgrammer 所以 Point point2 = SwingUtilities.convertPoint(label, new Point(0,0), panel21); 是这样的吗? - Nikolay Kuznetsov
1
这样更正确,它会将点0x0从“label”的坐标空间转换为坐标空间“panel21”。 - MadProgrammer
2个回答

7

对我来说,这是正确的行为。想象一下以下情况:主面板包含一个位置为x=0、y=100的子面板。如果你将主面板的0,0点转换为子面板,则返回值为0,-100。 实际上哪个组件是哪个组件的父级并不重要。逻辑是在父组件渲染子组件时添加(或减去)所有应用于图形的translate()调用。


@Nikolay Kuznetsov,你尝试过将不同的颜色添加为JPanel.setBackground,然后调整JFrame的大小吗?现在我明白了,在Stas回复之后,坐标是正确的,你将Point链接到另一个JPanel(而不是父级),所以有负数的数量 :-) - mKorbel
@mKorbel和Stas,请查看我的更新,我需要获取标签相对于panel21的位置。我的做法正确吗? - Nikolay Kuznetsov
我认为你上面提到的方法是正确的。Point point2 = SwingUtilities.convertPoint(label, new Point(0,0), panel21); - StanislavL

4

举个例子...

enter image description here

public class TestLocation01 {

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

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

                JPanel outter = new JPanel(new BorderLayout());
                outter.setBorder(new CompoundBorder(new LineBorder(Color.RED), new EmptyBorder(10, 10, 10, 10)));
                JPanel inner = new JPanel(new GridBagLayout());
                inner.setBorder(new CompoundBorder(new LineBorder(Color.BLUE), new EmptyBorder(10, 10, 10, 10)));
                JLabel label = new JLabel("Testing");
                inner.add(label);
                outter.add(inner);

                JLabel below = new JLabel("Below");

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(outter);
                frame.add(below, BorderLayout.SOUTH);
                frame.setSize(200, 200);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                System.out.println("lable.location: " + label.getLocation());
                System.out.println("label to inner: " + SwingUtilities.convertPoint(label, new Point(0, 0), inner));
                System.out.println("label to outter: " + SwingUtilities.convertPoint(label, new Point(0, 0), outter));
                System.out.println("label.parent to inner: " + SwingUtilities.convertPoint(label.getParent(), new Point(0, 0), inner));
                System.out.println("label.parent to outter: " + SwingUtilities.convertPoint(label.getParent(), new Point(0, 0), outter));
                System.out.println("label to frame: " + SwingUtilities.convertPoint(label, new Point(0, 0), frame));
                System.out.println("label.getParent to frame: " + SwingUtilities.convertPoint(label.getParent(), new Point(0, 0), frame));
                System.out.println("outter to label: " + SwingUtilities.convertPoint(outter, new Point(0, 0), label));
                System.out.println("label to below: " + SwingUtilities.convertPoint(label, new Point(0, 0), below));
                System.out.println("below to label: " + SwingUtilities.convertPoint(below, new Point(0, 0), label));
            }
        });
    }        
}

在我的系统中,执行这个命令会生成下列输出结果。
lable.location: java.awt.Point[x=65,y=62]
label to inner: java.awt.Point[x=65,y=62]
label to outter: java.awt.Point[x=76,y=73]
label.parent to inner: java.awt.Point[x=0,y=0]
label.parent to outter: java.awt.Point[x=11,y=11]
label to frame: java.awt.Point[x=76,y=95]
label.getParent to frame: java.awt.Point[x=11,y=33]
outter to label: java.awt.Point[x=-76,y=-73]
label to below: java.awt.Point[x=76,y=-89]
below to label: java.awt.Point[x=-76,y=89]

如果我将 label 作为源组件传递,那么我得到的是基于 label 和我试图转换其坐标空间的组件之间的关系而得出的相对位置。如果我传递 label 的父级,则使用的是父级坐标空间,这必然会产生不正确的结果。
如果您查看 labelbelow 之间的关系,负值结果就有意义了,因为 labelbelow 的上方和右侧。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接