views:

229

answers:

4

I'm attempting to make a Java Applet which will allow me to draw a graph data structure in a canvas by clicking where I want to create nodes, and clicking the nodes to connect them. The problem is I cannot get the paint() method to behave correctly. I add new nodes to the graph (and squares on the canvas) inside the mousePressed(MouseEvent e) method using,

Graphics g = this.getGraphics();

g.setColor(Color.blue);

g.fillRect(e.getX(), e.gety(), 40, 40);

Everything works fine, until I resize the window, and then all the filled rectangles vanish. I overrided the paint method to just an empty method, but the same thing still happens. I can't add the fillRect commands inside paint() because I don't know what rectangles exist until the user interacts with it using the mouse.

How can I use g.fillRect inside the mouse listener methods and make them stick?

+1  A: 

You've got to override the window resize action listener and call repaint inside of it.

monksy
+5  A: 

I don't know if I'm reading this correctly, but why not just store the location of the last click in a variable to be painted later, when the paint() method is called?

kyl
This is the right answer. `mousePressed()` doesn't need to do any painting of its own; it should just call `repaint` and save the necessary information so that `paint()` can do its job.
Jason Orendorff
Wouldn't I have to store the locations of all the clicks somewhere, and traverse through that list when I repaint? It's my understanding that paint() starts from an empty canvas and goes from there.
PherricOxide
@PherricOxide: Yes, you would. However, you'll have to do that no matter what solution you choose. You can't just assume the canvas is _never_ going to need to be repainted.
kyl
+4  A: 

The problem is the place you're drawing to isn't persistant. At any moment, you can lose everything you've drawn to it. The paint(Graphics) method is called when this happens. You'll either need to repaint the entire picture every time this happens, or you'll need to set aside a canvas to draw to and copy the contents to your applet's Graphics as needed.

Here's how to create and draw to an image:
http://java.sun.com/docs/books/tutorial/2d/images/drawonimage.html

Then, in your paint method, use your Graphics' drawImage(...) method to display the image you've created.

Gunslinger47
This seemed the easiest method, I created a new BufferedImage and then drew all my shapes on it, and just made the paint method draw the image. Thanks!
PherricOxide
No problem, though you might have to full repaints eventually so remember Kyl's advice. (also, remember to up-vote and "accept" answers you like. I want my karma points. :)
Gunslinger47
In this particular case, keeping the data would probably be a much better idea than a buffered image. However, +1 for getting both extremes.
Tom Hawtin - tackline
It's not mutually exclusive. For graphs in particular you'll likely want to do both. Keep the rendered graph in the image and quickly draw it to the screen on paint methods, but then do full redraws of the image only when it is updated. Full redraws on every paint can get very sluggish if you have many nodes.
Gunslinger47
A: 

The Graphics is temporary. When a region gets dirty, it will be repainted.

The best way is to create a BufferedImage, paint to it on mousePressed and call repaint.
When paint is called, draw the Image onto the passed Graphics Object. This way you don't need to store the Rectangles and you got a buffer which will improve performance.

Hardcoded