穿线油漆方法

Nic*_*ton 4 java swing multithreading paint event-dispatch-thread

我想知道如何编写以下代码,或者只是一个方法:

public void run (){

    public void paint(Graphics g) {
        g.fillRect(20, 20, 20, 20);
        for (int i = 20; i < 1000; i++) {
            g.fillRect(20, i, 20, 20);
            Thread.sleep(10);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我发现我无法创建此代码的线程,因为我得到了一个非法的表达式错误启动,这是公平的,但我没有看到解决方法.

Dav*_*amp 13

很难说出你在做什么,

但似乎你试图在其方法中覆盖paint()a .Runnablerun()

肯定不会这样做.

逻辑是

  • 拿一个组件
  • 覆盖其绘制方法以绘制我们需要的内容
  • 调用方法来更新矩形的坐标(或者在这种情况下,计时器会这样做)
  • 比调用repaint()组件所以可以再次调用paint方法并使用新的坐标重绘矩形(Timer也会在更改Rectangle的坐标后重新绘制)
  • 根据需要/需要重复最后两个步骤

(当我说组件我的意思是JPanel,paint方法指的是被覆盖paintComponent(..),JPanel因为这是最佳实践.)

一些建议:

1)不要覆盖paint而是使用JPanel和覆盖paintComponent.

2)不要忘记尊重油漆链并调用super.XXX重写的实现paintComponent(Graphics g)(或任何被覆盖的方法),除非故意将其删除.即

class MyPanel extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

         //do drawings here
    }
}
Run Code Online (Sandbox Code Playgroud)

3)如果paintComponent通常需要绘制它来覆盖getPreferredSize()并返回Dimension符合内容/图纸的s JPanel,即:

class MyPanel extends JPanel {
    @Override
    public Dimension getPreferredSize() {
         return new Dimension(300,300);
    }
}
Run Code Online (Sandbox Code Playgroud)

3)看Swing Timer,而不是Thread.sleep(..)作为sleep会阻塞GUI线程,并使它看起来被冻结.即

Timer t = new Timer(10, new AbstractAction() {
    int count = 20;
    @Override
    public void actionPerformed(ActionEvent ae) {
        if (count < 1000) {
            //increment rectangles y position
            //now repaint container so we can see changes in co-ordinates (unless you have a timer which repaints for you too)
            count++;
        } else {//counter is at 1000 stop the timer
            ((Timer) ae.getSource()).stop();
        }
    }
});
t.start();
Run Code Online (Sandbox Code Playgroud)

4)替代(因为我现在看到你只是将一个Rectangle不是Swing组件的东西)移动到Swing计时器TimerTask,并且只要在其run()方法中TimerTask不会创建/操作任何Swing组件,就可以使用它(因为不像Swing Timer那样在EDT上运行.注意revalidate()并且repaint()线程安全的,因此可以在其中使用TimerTask.

上述优点是EDT保持不必要的代码(即通过改变co-ords来移动AWT矩形)即

    final TimerTask tt = new TimerTask() {
        @Override
        public void run() {
            if (count < 1000) {
               //increment rectangles y position
                //now repaint container so we can see changes in co-ordinates (unless you have a timer which repaints for you too)
            count++;
            } else {//counter is at 1000 stop the timer
                cancel();
            }
        }
    };

    new Timer().scheduleAtFixedRate(tt, 0, 10);//start in 0milis and call run every 10 milis
Run Code Online (Sandbox Code Playgroud)