2

For some UI components in our application, we override paintComponent, which under some conditions "recursively" calls itself by invoking repaint. We use this approach to achieve high refresh rate of animations in the component.

For instance, a progress bar we use looks something like:

public class SimpleProgressBar extends JPanel {
    private boolean inProgress;

    ....

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

Is this a good practice (especially in terms of performance / efficiency / CPU usage)?
Is it better to use a Timer or a background thread to repaint our components?

Elist
  • 5,313
  • 3
  • 35
  • 73

2 Answers2

6

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

No, it is not good practice. Calling repaint from within paintComponent is bad practice because:

  1. A high frame rate like this is virtually never required
  2. The frame rate is not guaranteed (repaint does not directly call the painting method, but causes a call to this component's paint method as soon as possible' (which may not be immediately))
  3. Places priority on painting of a single component, and can result in poor performance not only in painting of that one component, but also painting of other Components as well as response to other EDT specific tasks (eg events)

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

Yes, using a Timer or Thread gives you much better control over the frame rate, without bogging down the EDT while doing so. Depending upon the context, a Timer runs on the EDT (as opposed to a Thread) so no dispatching to the EDT is required.

copeg
  • 8,290
  • 19
  • 28
  • Your points on performance makes sense. Yet I find it much simpler to use the recursive approach. I often find myself running a code that uses multiple threads to keep track of a simple timed task, threads that are really hard to control their life-cycle and maintain during re factorization. Therefore, my question is, how bad is the impact over performance in this case? How can I test it? And what if this kind of high-rate tasks are rare? – Elist May 31 '15 at 20:07
  • I recommend stress testing it to see. For *very* simple UI, you may not notice any issue. Here's a simple scenario in which performance already takes a hit on my system: drawing 100x100 tiles 10x vertically and horizontally (similar to background tiles in a game) - `JButton` and `MouseMotionListener` response times already takes a performance hit – copeg May 31 '15 at 20:45
  • Thanks! I'll run some more tests on my environment. – Elist May 31 '15 at 20:53
  • +1 I've drawn [tens of thousands of lines in an animation](http://java-articles.info/articles/?p=614) without having a problem with flickering. – Gilbert Le Blanc May 31 '15 at 20:59
0

There are very few situations where overriding paintComponent is a good thing. Your situation seems to be one of them; however, it is important to remember that it is not your job to call paintComponent. What I mean by this, is that it is an office of the System to decide when to repaint certain components. This is especially evident when you drag the screen around, or when you put another screen over yours. That being said, it is very difficult to say how many times your method will be called; therein, making it difficult to say when it would be worth using that implementation.
On a side note, a background thread, as you put it, would more than likely not make it better, and Swing is notoriously not thread-safe.
I hope this helps, and best of luck to you!

Zesty Memes
  • 442
  • 2
  • 11
  • First, thanks a lot for the quick answer. I have overridden `paintComponent` a dozen times to achieve customized controls / components, and I find it very useful. Can you be more specific as for what would be the downside of using a background thread? – Elist May 31 '15 at 19:39
  • My apologies if I seemed off-putting or indignant in my saying against `paintComponent()`: it's not very often that people implement it correctly; however, good on you. As for why it is best not to use multiple threads, it can be found that there is a lot of space for error in Swing and AWT/similar items. I'm not the best at explaining these sorts of things, but [here is a bit of reading that may shed some more light](http://stackoverflow.com/questions/7984870/multithreading-for-java-graphics). – Zesty Memes May 31 '15 at 19:48
  • @Elist take a looksie at copeg 's answer. That may help you better than what I can provide XD. – Zesty Memes May 31 '15 at 19:58