从 paintComponent 调用重绘是一个好习惯

Is calling repaint from paintComponent a good practice

对于我们应用程序中的某些 UI 组件,我们覆盖 paintComponent,在某些情况下 "recursively" 通过调用 repaint 调用自身。我们使用这种方式来实现组件中动画的高刷新率。

例如,我们使用的进度条类似于:

public class SimpleProgressBar extends JPanel {
    private boolean inProgress;

    ....

    @Override
    protected void paintComponent(Graphics g) {
        if (inProgress) {
            paintBar(g);
            repaint();
        } else {
            doSomeOtherThings();
        }
    }
}

这是一个好的做法吗(尤其是在性能/效率/CPU 使用方面)?
repaint 我们的组件使用 Timer 还是后台线程更好?

在极少数情况下,覆盖 paintComponent 是一件好事。您的情况似乎就是其中之一;但是,重要的是要记住,调用 paintComponent 不是你的工作。我的意思是,它是系统的一个办公室,可以决定何时重新绘制某些组件。当您四处拖动屏幕或将另一个屏幕放在您的屏幕上时,这一点尤其明显。话虽如此,很难说您的方法将被调用多少次;其中,很难说什么时候值得使用该实现。
附带说明一下,正如您所说,后台线程很可能不会使它变得更好,众所周知,Swing 不是线程-safe.
希望对你有所帮助,祝你好运!

Is this a good practice (especially in terms of performance / efficiency / CPU usage)?

不,这不是好的做法。从 paintComponent 内部调用 repaint 是不好的做法,因为:

  1. 几乎不需要这样的高帧率
  2. 不保证帧率(repaint不直接调用绘画方法,而是尽快调用此组件的绘画方法'(可能不是立即))
  3. 优先绘制单个组件,不仅会导致该组件的绘制性能不佳,还会导致其他组件的绘制以及响应其他 EDT 特定任务(例如事件)

Is it better to use a Timer or a background thread to repaint our components?

是的,使用 TimerThread 可以更好地控制帧速率,而不会在这样做时拖慢 EDT。根据上下文,Timer 在 EDT 上运行(而不是线程),因此不需要分派到 EDT。