为什么必须在 paintComponent() 内部初始化 x 和 y 坐标?

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

练习 1609编写一个使用箭头键绘制线段的程序。当按下右箭头键、上箭头键、左箭头键或下箭头键时,该线从框架的中心开始向东、北、西或南绘制。简而言之,画一个迷宫。有关我的问题的描述,请参阅下面的评论。

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

            }
        }

    }

如果我尝试在其他地方初始化 x 和 y,最后一行 System.out.println(x + " " + y); 输出 0,0 但是 paintComponent()。在 paintcomponent() 内部初始化时,输出为 292,131...这就是我想要的。

getWidth()getHeight() 在 UI 元素通过布局通道之前未正确设置。这保证在调用 paintComponent() 之前发生,但可能不会在您尝试调用它们的其他点发生。

参见:getWidth() and getHeight() are 0 after calling setPreferredSize()

如果需要在组件宽高为set/changed时得到通知,查看ComponentListenerhttp://docs.oracle.com/javase/7/docs/api/java/awt/event/ComponentListener.html