Home > Back-end >  Can't get absolute JLabel location
Can't get absolute JLabel location

Time:06-23

My JFrame uses a BorderLayout and it has a JLabel nested in several panels with different layout mangers. I've tried several methods, however, cannot get the true position of where it sits in the JFrame.

I made a test UI and it seems like when other components are added the getX and getY paramaters do not update. Other methods like getLocation do not provide a correct result either. Is there any way to obtain the exaclt location without manually calculating every possible offset from each component.

I am tracking the stated positions of the label (content) using a similar sized panel called content2 in the glass pane which I want to sit underneath content perfectly

public class test {
    private Dimension pSize = new Dimension(100,100);
    private JFrame frame = new JFrame();
    
    public static void main(String[] args) {
        new test();

    }
    
    public test() {
        
        
        //setup frame basics
        frame.setPreferredSize(new Dimension(500,500));
        frame.setLayout(new BorderLayout());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        // setup GUI
        JMenuBar j = new JMenuBar();
        JMenuItem a = new JMenuItem("lol");
        j.add(a);
        
        JPanel j2 = new JPanel();
        
        
        
        //setup main panel
        JPanel main = new JPanel();
        main.setBackground(Color.DARK_GRAY);
        //setup side panel
        FlowLayout f1 = new FlowLayout(FlowLayout.LEADING);
        f1.setHgap(10);
        f1.setVgap(0);
        JPanel side = new JPanel();
        side.setLayout(new BorderLayout());
        side.setBackground(Color.gray);
        side.setPreferredSize(new Dimension(150,100));
    
        //setup JLabel (the main focus)
        JLabel content = new JLabel("a");
        content.setOpaque(true);
        content.setBackground(Color.blue);
        content.setPreferredSize(pSize);
        
        // Setup the internal panels of side
        JPanel top = new JPanel();//The panel where CONTENT is, the main focus 
        JPanel bot = new JPanel();
        top.setBackground(Color.WHITE); 
        bot.setBackground(Color.orange);
        top.setLayout(f1);
        top.add(content); 
        
        side.add(top, BorderLayout.NORTH); 
        side.add(bot, BorderLayout.CENTER);
        
        frame.add(main, BorderLayout.CENTER);
        frame.add(side, BorderLayout.WEST);
        frame.add(j2, BorderLayout.NORTH);
        frame.setJMenuBar(j);
        
        frame.pack();
        frame.setVisible(true);
        
        //Setting up the glass panel
        JPanel pane = new JPanel();
        pane.setLayout(null);
        pane.setOpaque(false);
        JPanel content2 = new JPanel();
        content2.setBackground(Color.red);
        
        content.revalidate();
        int x = content.getX();
        int y = content.getY();
        
        
        
        // y = (int) content.getLocation().getY(); //returns a completely wrong location
        //y = (int) content.getLocationOnScreen(); //returns a completely wrong location
        
        /*
        Point p = new Point();
        p.setLocation(x, y);
        
        p = SwingUtilities.convertPoint(content2, x, y, frame);
        
        //SwingUtilities.convertPoint(content, p, frame);
        
        y = (int) p.getY();
        
        
         * 
         * Tried multiple SwingUtility converions to no avail
         * 
         */
        
        // y = y  j.getHeight()   j2.getHeight(); // Manually calculating the Y off set works successfully but is too tedious for large project
        y = y   content.getHeight();
        content2.setBounds(x,y,100,100);
        
        pane.add(content2);
        
        frame.setGlassPane(pane);
        frame.getGlassPane().setVisible(true);
        frame.pack();
        
    }

}
    //frame.getContentPane().add(content);
        //frame.add(content);
        
        frame.setPreferredSize(new Dimension(500,500));
        
        content.setBorder(BorderFactory.createEmptyBorder());
        side.setLayout(new BorderLayout());
        
        JPanel top = new JPanel();
        JPanel bot = new JPanel();
        top.setBackground(Color.WHITE);
        bot.setBackground(Color.orange);
        
        side.add(top, BorderLayout.NORTH);
        
        top.setLayout(f1);
        top.add(content);
        
        side.add(bot, BorderLayout.CENTER);

        frame.add(main, BorderLayout.CENTER);
        frame.add(j2, BorderLayout.NORTH);
        frame.add(side, BorderLayout.WEST);
        
        frame.pack();
        frame.setVisible(true);
        JPanel pane = new JPanel();
        pane.setLayout(null);
        pane.setOpaque(false);
        JPanel content2 = new JPanel();
        content2.setBackground(Color.red);
        
        content.revalidate();
        int x = content.getX();
        int y = content.getY();
        // y = y  j.getHeight()   j2.getHeight();
         
         
        
        
         
        y = y   content.getHeight();
        content2.setBounds(x,y,100,100);
        
        pane.add(content2);
        
        frame.setGlassPane(pane);
        frame.getGlassPane().setVisible(true);
        frame.pack();
        
    }

}

CodePudding user response:

Conceptually you could make use of enter image description here

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;

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

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                GlassPane glassPane = new GlassPane();
                JFrame frame = new JFrame();
                frame.setGlassPane(glassPane);
                frame.add(new MainPane(glassPane));
                glassPane.setVisible(true);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface Tracker {
        public void addTrackable(Trackable trackable);
        public void removeTrackable(Trackable trackable);
    }

    public interface Trackable {
        public JComponent[] getTrackedComponents();
    }

    public class MainPane extends JPanel {

        private JLabel label = new JLabel("Catch me if you can");

        public MainPane(Tracker tracker) {
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(32, 32, 32, 32));
            add(label);

            tracker.addTrackable(new Trackable() {
                @Override
                public JComponent[] getTrackedComponents() {
                    return new JComponent[] { label };
                }
            });
        }

    }

    public class GlassPane extends JPanel implements Tracker {

        private List<Trackable> trackables = new ArrayList<>(8);

        public GlassPane() {
            setOpaque(false);
        }

        @Override
        public void addTrackable(Trackable trackable) {
            trackables.add(trackable);
            revalidate();
            repaint();
        }

        @Override
        public void removeTrackable(Trackable trackable) {
            trackables.remove(trackable);
            revalidate();
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            for (Trackable trackable : trackables) {
                for (JComponent component : trackable.getTrackedComponents()) {
                    Rectangle relativeBounds = SwingUtilities.convertRectangle(component.getParent(), component.getBounds(), this);
                    g2d.draw(relativeBounds);
                }
            }
            g2d.dispose();
        }

    }
}

Well, that's pretty boring, it's one component inside one container, let's trying something a little more complicated...

enter image description here

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

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

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                GlassPane glassPane = new GlassPane();
                JFrame frame = new JFrame();
                frame.setLayout(new GridLayout(2, 2, 8, 8));

                frame.add(new MainPane(glassPane));
                frame.add(new MainPane(glassPane));
                frame.add(new MainPane(glassPane));
                frame.add(new MainPane(glassPane));

                frame.setGlassPane(glassPane);
                glassPane.setVisible(true);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface Tracker {
        public void addTrackable(Trackable trackable);

        public void removeTrackable(Trackable trackable);
    }

    public interface Trackable {
        public JComponent[] getTrackedComponents();
    }

    public class MainPane extends JPanel {

        private JLabel label = new JLabel("Catch me if you can");

        public MainPane(Tracker tracker) {
            setLayout(new GridBagLayout());
            setBorder(new CompoundBorder(new LineBorder(Color.DARK_GRAY, 1, true), new EmptyBorder(32, 32, 32, 32)));
            add(label);

            tracker.addTrackable(new Trackable() {
                @Override
                public JComponent[] getTrackedComponents() {
                    return new JComponent[]{label};
                }
            });
        }

    }

    public class GlassPane extends JPanel implements Tracker {

        private List<Trackable> trackables = new ArrayList<>(8);
        private List<Color> masterColors = new ArrayList<>(Arrays.asList(new Color[]{
            Color.RED,
            Color.GREEN,
            Color.BLUE,
            Color.CYAN,
            Color.DARK_GRAY,
            Color.GRAY,
            Color.MAGENTA,
            Color.ORANGE,
            Color.PINK,
            Color.YELLOW,}));

        public GlassPane() {
            setOpaque(false);
        }

        @Override
        public void addTrackable(Trackable trackable) {
            trackables.add(trackable);
            revalidate();
            repaint();
        }

        @Override
        public void removeTrackable(Trackable trackable) {
            trackables.remove(trackable);
            revalidate();
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            List<Color> colors = new ArrayList<>(masterColors);
            for (Trackable trackable : trackables) {
                for (JComponent component : trackable.getTrackedComponents()) {
                    if (colors.isEmpty()) {
                        colors = new ArrayList<>(masterColors);
                    }
                    g2d.setColor(colors.remove(0));
                    Rectangle relativeBounds = SwingUtilities.convertRectangle(component.getParent(), component.getBounds(), this);
                    g2d.draw(relativeBounds);
                }
            }
            g2d.dispose();
        }

    }
}

CodePudding user response:

If you have the coordinate within the component, transfer it to screen coordinates using your component's convertPointToScreen(). Afterwards you can transfer back to see where in the window it sits by using the frame's convertPointFromScreen().

Or eliminate one of the two steps by directly using convertPoint().

  • Related