【问题标题】:Threading a paint method线程绘制方法
【发布时间】:2020-12-22 15:19:06
【问题描述】:

我想知道如何线程化以下代码,或者只是一般的方法:

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

我发现我无法创建此代码的线程,因为我得到了一个非法的表达式开始错误,这是公平的,但我没有找到解决办法。

【问题讨论】:

  • 不允许在 Gui 线程之外进行绘画。您不能将绘图重定向到辅助线程。

标签: java multithreading swing paintcomponent event-dispatch-thread


【解决方案1】:

很难说你在做什么,

但您似乎正试图从其run() 方法中覆盖Runnablepaint()

这肯定做不到。

逻辑是

  • 取一个组件
  • 重写它的paint方法来绘制我们需要的东西
  • 调用方法来更新矩形的坐标(或者在这种情况下计时器会这样做)
  • 比在组件上调用repaint(),因此可以再次调用paint方法并使用其新坐标重绘矩形(定时器也会在更改矩形坐标后负责重绘)
  • 根据需要/想要多次重复最后 2 个步骤

(当我说 component 我实际上是指 JPanelpaint 方法 指的是 JPanel 的覆盖 paintComponent(..),因为这是最佳实践。)

一些建议:

1) 不要覆盖paint,而是使用JPanel 并覆盖paintComponent

2) 不要忘记尊重 绘制链 并调用覆盖 paintComponent(Graphics g)(或任何覆盖该事实的方法)的 super.XXX 实现,除非故意将其省略。即

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

         //do drawings here
    }
}

3) 如果在paintComponent 中绘图,通常需要覆盖getPreferredSize() 并返回适合JPanel 的内容/绘图的Dimensions,即:

class MyPanel extends JPanel {
    @Override
    public Dimension getPreferredSize() {
         return new Dimension(300,300);
    }
}

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

4) 另一种选择(因为我现在看到您只是将不是 Swing 组件的 Rectangle 移动)到 Swing 计时器是 TimerTask,只要不会创建 Swing 组件,就可以使用它/从其 run() 方法中进行操作(因为 TimerTask 不像 Swing Timer 那样在 EDT 上运行)。注意revalidate()repaint()线程安全的,所以它可以在TimerTask 中使用。

上述的优点是保留了 EDT 的不必要代码(即通过更改坐标移动 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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-31
  • 1970-01-01
  • 2012-06-30
相关资源
最近更新 更多