Nikolay Kuznetsov
Nikolay Kuznetsov

Reputation: 9579

Why JLabel.getLocationOnScreen() returns diffirently depending on parent JPanel Layout

I use Jave Swing and the simplified hierarchy can be understood as JFrame -> JPanel -> JLabel.

Now I have options of adding JLabel into JPanel:

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

This is common configuration I am doing in both cases

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

Even though I keep all other code unchanged the following method call gives very different results:

    Point location = getLocationOnFrame(label);

I call this method to identify location of JLabel relative to 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;
    }

These are results from System.out.println() even though visiually the label appears in the same place.

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]

It seems to me that in 2nd case the numbers come from the left-top corner of parent JPanel not JLabel itself.

Basically I am trying to use the code from 2nd case and get numbers from 1st.

Upvotes: 1

Views: 661

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347194

As to why you're getting different results, I have absolutely no idea.

However, I believe you're making more work for your self...

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

Will convert the labels coordinates to the windows coordinate space for you.

Know remember, the location of the frame is the top left corner of the frame (no, really it is ;)), but your label exists within the frame's contentPane which is offset within the frames border, so depending on what you are trying to do, you may be better using the contentPane instead of the frame ;)

This is a simple example I used to test the logic ;)

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

        }

    }

}

Upvotes: 3

Related Questions