Join 150,381 Java Programmers for FREE! Get instant access to thousands of Java experts, tutorials, code snippets, and more! There are 1,206 people online right now. Registration is fast and FREE... Join Now!
Hello, I have programmed a simple Java Swing program that draws three houses and has the sun slowly cross the sky above the houses. Every time the sun has to move, I have to redraw the sun. However, the houses never change and yet I have to redraw them every time. On a small program like this it is no big deal, but in a game-like program it would seem to me that that could waste CPU time and slow everything down since you are redrawing the same thing over and over again. Is there a way to only draw something that never changes once? Or do you have to draw it every single component every single time any component changes, as I have done?
Second question. I am trying to draw the background blue since I want the sky to be blue. I have put this into my "SunsetComponent" class's "paintComponent" function. I get no errors but the background does not change to blue. Is this because SunsetComponent extends JComponent rather than JWindow or JPanel? I have successfully changed the background when I had more complex programs that included several JPanels and JWindows. However, this program is all just one big JFrame and doesn't need any JPanels or JWindows. Is there a way to change the background color? My code is below and it works except for the background color. Thank you.
CODE
// Filename : Sunset.java
import java.awt.*; import javax.swing.*;
public class Sunset { public static void main(String[] args) { int initialWindowWidth = 400; int initialWindowHeight = 400; JFrame frame = new JFrame ("Sunset"); frame.add (new SunsetComponent ()); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setSize (initialWindowWidth, initialWindowHeight); frame.setVisible (true); } }
class SunsetComponent extends JComponent implements Runnable { int sunVertPos = 100; int sunHorizPos = 50; int sunDiameter = 50;
public SunsetComponent () { Thread t = new Thread (this); t.start (); }
public void paintComponent (Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setBackground (Color.blue); // does not color background blue DrawHouses (g2); g2.setPaint (Color.orange); g2.fillOval (sunHorizPos, sunVertPos, sunDiameter, sunDiameter); }
public void DrawHouses (Graphics2D g2) { int vert = 300; int horiz = 40; int size = 50; for (int i = 0; i < 3; i++) { g2.setPaint (Color.red); g2.fillRect(horiz, vert, size, size); int x[] = {horiz - 20, horiz + size + 20, horiz + size / 2}; int y[] = {vert, vert, vert - size};
You're on the right track. JComponent is the bottom of the function stack for swing components. It expects you to do all the redraws yourself on paint. In contrast, the JPanel has a builtin screen buffer and keeps everything you've ever drawn.
I modified your code slightly using JPanel. Run in and then switch is to JComponent to see the difference.
CODE
import java.awt.*; import javax.swing.*;
//public class Sunset2 extends JComponent implements Runnable { public class Sunset2 extends JPanel implements Runnable { private int sunVertPos = 100; private int sunHorizPos = 50; private int sunDiameter = 50; private boolean needDrawHouse = true;
public Sunset2 () { Thread t = new Thread (this); t.start (); }
public void paintComponent (Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //g2.setBackground (Color.blue); // does not color background blue DrawHouses (g2); drawSun(g2); }
private void DrawHouses (Graphics2D g2) { if (!needDrawHouse) { return; } g2.setBackground (Color.blue); // does not color background blue g2.clearRect(0,0,this.getWidth(), this.getHeight());
//g2.setPaint (Color.blue); //g2.fillRect(0,0,this.getWidth(), this.getHeight()); needDrawHouse = false; int vert = 300; int horiz = 40; int size = 50; for (int i = 0; i < 3; i++) { g2.setPaint (Color.red); g2.fillRect(horiz, vert, size, size); int x[] = {horiz - 20, horiz + size + 20, horiz + size / 2}; int y[] = {vert, vert, vert - size}; g2.setPaint (Color.green); g2.fillPolygon(x, y, 3); horiz = horiz + 110; } }
public void run () { try { while (true) { if (sunHorizPos > 300) sunHorizPos = 50; repaint(); sunHorizPos = sunHorizPos + 10; Thread.sleep (300); } } catch (InterruptedException ie) { } }
public static void main(String[] args) { JFrame frame = new JFrame ("Sunset"); frame.add (new Sunset2()); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setSize (400, 400); frame.setVisible (true); } }
A reasonable solution is to is erase the previously drawn sun on JPanel. For JComponent, you usually want to maintain your own offscreen image. Look into Java Double Buffering for more info.
Cool. Thanks. I'm experimenting with that clearRect function. There appears to be no equivalent clearOval function (sun is oval). Haven't quite got the hang of clearRect yet, but getting there. The houses stay there without being repainted, which is good. The sun streaks across the sky and doesn't erase itself (which is obviously why I need to add clearRect). I did try the regular old "fillOval" and "fillRect" over the old sun, using the background color. That works. I'll continue experimenting with clearRect, but is there a reason why clearRect is preferable to fillRect using the background color? Are they identical?
is there a reason why clearRect is preferable to fillRect using the background color? Are they identical?
To be honest, I never use clearRect, it was primarily to show that the background color was being used for something. Depending on the graphic context, I believe clearRect will behave differently than fillRect. However, default behavior is identical, so unless you're doing something special, I'd just use fillRect.