Search code examples
javapaintcomponent

Why must x and y coordinates be initialized inside paintComponent()?


Exercise1609: Write a program that draws line segments using the arrow keys. The line starts from the center of the frame and draws towards east,north, west, or south when the right-arrow key, up-arrow key, left-arrow key, or down-arrow key is pressed. In short, draw a maze. See comments below for a description of my question.

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.JFrame;
    import javax.swing.JPanel;

    public class Exercise1609 extends JFrame {

        private KeyboardPanel panel = new KeyboardPanel();

        public Exercise1609() {
            add(panel);
            panel.setFocusable(true);
        }

        public static void main(String[] args) {
            Exercise1609 frame = new Exercise1609();
            frame.setTitle("Tegn med piltaster");
            frame.setSize(600, 300);
            frame.setLocationRelativeTo(null);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }

       //The panel that listens for key and responds by drawing             
       public static class KeyboardPanel extends JPanel {

            private int x,y,previousX,previousY;
            private boolean firstTime = true;

            public KeyboardPanel() {

                /**
                 * why must x and y be initialized inside paintComponent? 
                 * if I want to start drawing from the middle of the panel?
                 * If I remove the if-block inside paintComponent and instead
                 * place the initialization here, as shown with the two lines below:
                 * x = previousX = getWidth() / 2;
                 * y = previousY = getHeight() / 2;
                 * ...then the program will not start to draw from the middle,
                 * but upper left corner of the screen
                 */
                addKeyListener(new KeyAdapter() {
                    @Override
                    public void keyPressed(KeyEvent e) {
                        previousY = y;
                        previousX = x;          
                        switch (e.getKeyCode()) {
                        case KeyEvent.VK_DOWN:
                            y++;
                            break;
                        case KeyEvent.VK_UP:        
                            y--;
                            break;
                        case KeyEvent.VK_RIGHT:
                            x++;
                            break;
                        case KeyEvent.VK_LEFT:
                            x--;
                            break;
                        }
                        repaint();
                    }
                });
            }//end constructor

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponents(g);

                if(firstTime) {
                 //Why can't x and y be initialized outiside paintComponent?
                 //Why can't they be initialized inside the constructor of this class?
                 x = previousX = getWidth() / 2;
                 y = previousY = getHeight() / 2;
                 firstTime = false;
                }
                g.drawLine(previousX, previousY, x, y);
                System.out.println(x + " " + y);

            }
        }

    }

The last line System.out.println(x + " " + y); outputs 0,0 if I try to initialize x and y anywhere else but paintComponent(). When initialized inside paintcomponent() the output is 292,131...which is what I want.


Solution

  • getWidth() and getHeight() are not set correctly until the UI elements have gone through a layout pass. This is guaranteed to happen before paintComponent() is called but probably not at other points where you have tried to call them.

    See: getWidth() and getHeight() are 0 after calling setPreferredSize()

    If you need to be notified when the width and height of the component is set/changed, check out ComponentListener: http://docs.oracle.com/javase/7/docs/api/java/awt/event/ComponentListener.html