Search code examples
javaswingawtjava-2d

Why do I have to set the position of my JLabel on every paintComponent?


I want to use a JLabel in a very simple environment but I'm wondering why I have to set the location on every repaint.

Code:

public class Example {
    public static void main(String[] args) {
        JFrame frame = buildFrame();
        TestPane pane = new TestPane();

        frame.add(pane);

        while (true) {
            pane.repaint();
            frame.setVisible(true);
        }
    }

    private static JFrame buildFrame() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(480, 272);
        frame.setVisible(true);
        return frame;
    }
}

public class TestPane extends JPanel {
    JLabel testLabel = new JLabel("TEST");

    TestPane() {
        super();
        add(testLabel);
        testLabel.setLocation(200, 200);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        testLabel.setLocation(200, 200); // without this line, the label will always be at the top center
    }
}

The loop-based layout comes from various animations with images I'm doing. Why does the repaint always reset the location of all labels so I have to setLocation on every paintComponent?


Solution

  • why I have to set the location on every repaint.

    You don't. Actually, you should never set the position or any kind of constraint of a component inside paintComponent method. paintComponent method is only for painting, not for orientation or anything else.

    When you jpanel.add(myComponent, constraints) component's position will be decided by container's current LayoutManager. (When you jpanel.add(myComponent); without any constraints, the default constraints will take place, with every layout manager having its own default).

    The label is placed at the top of the panel because you do not set the layout of the panel, so it has its default, which is FlowLayout. In order to change it you will have to use another layout manager with the proper constraints.

    For example, in order to place it at the center of the panel, you must do:

    jpanel.setLayout(new BorderLayout());
    jpanel.add(myLabel,BorderLayout.CENTER);
    

    Finally doing while(true) inside the Thread where you GUI is running, it will hang the thread, means that the GUI will be "frozen" since events cannot take place.