0

I've got a problem with Swing, I'm trying to understand how the paintComponent works and I just don't get why in this case it gets called twice or even thrice (it seems to be randomly called to me).

package paintComponentTest;

import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class UI {

public static void main(String[] args) {
    JFrame testFrame = new JFrame();

    TestPanel testPanel = new TestPanel();
    testFrame.setContentPane(testPanel);

    testFrame.setSize(500, 500);
    testFrame.setVisible(true);
}
}

class TestPanel extends JPanel {

@Override
public void paintComponent(Graphics g) {
    System.out.println("Called");
}
}    

I'm working on a different project and my paintComponent also gets called several times whereas I'd like it only to be called once and it prevents me from going forward.

Thanks in advance !

CARREAU Clément
  • 657
  • 5
  • 16
  • 1
    I little more information over "why" you only ever want `paintComponent` to be called once would go along way to been able to provide you with a solution to your problem, because this is not how painting works (or could work) – MadProgrammer Mar 27 '14 at 23:33

1 Answers1

3

Basically, painting is outside of your control and there is (very little) you can do about.

paintComponent is called (indirectly) when the repaint manager decides that the component needs to be re-painted because of some event, such as the component been re-sized (directly or because the parent container was resized) or it has become displayable (now visible on the screen or added to a component that is displayable) and any number of system events.

The first thing you need to do (apart from calling super.paintComponent before you do any custom painting) is to relinquish the illusion of control you might think you have over the paint process.

Next, you should read through Painting in AWT and Swing and understand how the painting process works.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thank you for answering that fast. I've got the `super.paintComponent` before any repainting in my `paintComponent`. The fact is, I've got some processing to do in my `paintComponent` and the first time it is called I CAN'T DO THE PROCESSING since not everything has been created etc .... I won't go into details but I have to wait for the 2nd call of my JPanel `paintComponent` otherwise it won't work. As a result I'm kinda using a flag to determine if I'm in the first call and I find it very ugly but I don't know how to do it otherwise. Anyway, thank you I'm gonna read this article. – CARREAU Clément Mar 27 '14 at 23:47
  • A solution might be to use a `BufferedImage` to paint what you want when you're ready and then paint the `BufferedImage` in the `paintComponent` method. Two reasons for this. You gain control and painting should be done as fast as possible, this will prevent any possible lag in your applications responsiveness... – MadProgrammer Mar 27 '14 at 23:49
  • @user2007740 There should not be any level of processing that **must** be done in `paintComponent` only once. You should be able to use init methods and constructors to get your "one-time-only" things out of the way... – MirroredFate Mar 27 '14 at 23:52
  • @user2007740 A possible [example of a back buffer](http://stackoverflow.com/questions/18839821/incremental-graphics-in-swing/18839956#18839956) – MadProgrammer Mar 27 '14 at 23:52
  • @MirroredFate thing is in my `paintComponent` I'm drawing shapes on my JPanel and then I check if I've got data to load and if I do, I'm drawing something else. The problem is, the first call of `paintComponent` call my drawSmth methods but nothing appear, and so, when it's trying to draw something else it fails since it's based on what was previously drawn. It's kind of hard to explain but in my case the first call does absolutely nothing, and that's why I need to use a boolean to be sure things have been drawn at least once. – CARREAU Clément Mar 28 '14 at 06:29
  • 1
    @user2007740 You paint code needs to be responsive and should represent the currently known state. If you need to do processing or wait for something, then you shouldn't be doing it in your paint methods ... or in fact, in the Event Dispatching Thread at all, this will make your application look like it's "stopped" – MadProgrammer Mar 28 '14 at 06:31
  • It does represent the currently known state. It's just that the first time `paintComponent` is called, even though I'm calling my `drawSmth` methods, nothing is drawn. But once `paintComponent` has been called once, it's ok, everything works fine and draws perfectly. – CARREAU Clément Mar 28 '14 at 06:41