Problems with super.paintComponent();

Why is this important?
super.paintComponent() is normally called as one of the first lines in your own paintComponent() method, the one that you get when you make a subclass of JPanel.

What does it do?

This runs the paintComponent() method of the JPanel class. What this standard paintComponent method does is to completely repaint the screen with the backround colour, thus essentially clearing it and repaiting it with the background colour.

There are two potential problems with this:

  1. if you're doing a lot of animation, redrawing the whole screen repeatedly will cause flicker
  2. sometimes you show a drawing evolving over time and clearing the screen will erase everything you've done.

Let's assume that the drawing that we're doing requires a black background. How do we get this to show up only once, and then never get cleared?

Possible solutions:

with sample code

1. add a flag or sentinel:

boolean firstTime = true; public void paintComponent(Graphics g) { /******* trying various methods to get the background to only paint once. ********/ if (firstTime) { super.paintComponent(g); firstTime = false; } //rest of method does the painting

This DOES NOT WORK. I think that it might actually run before the JPanel is displayed, and then when it's displayed, it gets shown with the default gray background.

2. Use the isVisible() method of the JPanel

boolean firstTime = true; public void paintComponent(Graphics g) { /******* trying various methods to get the background to only paint once. ********/ if(this.isVisible()) { if (firstTime) { super.paintComponent(g); firstTime = false; } } //rest of method does the painting

This DOES NOT WORK. I don't know why.

3. Try and detect the size of the JPanel.

When the JPanel is first created its size is (0,0). It only gets a size when it is displayed, so keep clearing and redrawing the background until the size is more than 10 pixels wide.

boolean firstTime = true; public void paintComponent(Graphics g) { if (firstTime) { super.paintComponent(g); scrW = this.getWidth(); scrH = this.getHeight(); cx = scrW/2; cy = scrH/2; if (cx > 10) firstTime = false; return; }

This DOES NOT WORK. I don't know why.

4. Use a counter. Just keep clearing the screen for a while until it starts working right.

private int countDown = 10; public void paintComponent(Graphics g) { if (countDown > 0) { super.paintComponent(g); countDown--; return; }

This works!!! countDown can be reduced down to about 6 and it still works. Below that the background doesn't draw.

This is a bit of a kludge though. It's kind of embarassing that Java Swing doesn't have a proper draw system that tells you when something is first visible.

Now that it's working, you can add in the code that calculated the centre of the screen:

private int countDown = 10; public void paintComponent(Graphics g) { if (countDown > 0) { scrW = this.getWidth(); scrH = this.getHeight(); cx = scrW/2; cy = scrH/2; super.paintComponent(g); countDown--; return; } All that this does is it stops the program for having to recalculate the centre of the screen every time that the JPanel is redrawn.

5. Use a method to check the background colour of a specific pixel to see if the background has been drawn yet or not.

public void paintComponent(Graphics g) { try { java.awt.Robot rb = new java.awt.Robot(); Color pixel = rb.getPixelColor(100,100);//gets the color of the pixel at screen coordinate 0,0. if (pixel.getRed() > 0) { // if the background is any shade of gray (or red) super.paintComponent(g); } } catch (AWTException e) { e.printStackTrace(); System.exit(0); }

This works!! BUT it is REALLY slow and slows the program down tremendously.

It's too much work to create a robot object and get the pixel every single time we draw the screen. Even moving the creation of the rb object to the DrawingPanel constructor does not speed the program up. It's the getPixelColor that is slowing it down.

6. Check to see if the JFrame has been resized.

This works only when a timer is used as well (for some reason). What happens is when the JFrame is first drawn, it is resized from (0,0) to the size that you specify via setSize() or pack(). This event only happens when the screen is resized, so we're not using a lot of resources checking something every time we draw the screen.

... code to come ...

7. BEST WAY: draw on a BufferedImage and then display the buffered image on the JPanel whenever you want to.

Please see Spiral.java