Java Forum / First Aid / September 2003
Glasspane and Saving Graphics
Bryan R. Meyer - 13 Sep 2003 22:16 GMT Hello All -
I am writing a program that puts HTML in a JEditorPane object which is then placed in a JFrame object. I have a class (called TestCanvas) which inherits from Canvas and which I use as the glasspane for the JFrame. Using the mouse, I can draw lines on the glasspane. This works beautifully. However, when the JFrame is not in focus or if I set the glasspane to be invisible and then make it visible again, not all of the markings that I made on the glasspane remain. Only the last line I drew shows up when the JFrame is put back in focus or the glasspane is set to be visible.
The code for the TestCanvas class is below. I suspect I have to save the Graphics context. Perhaps to an offscreen image? My attempts at this have been unsuccessful. I'd appreciate any insight. Thanks. -Bryan
class TestCanvas extends JComponent implements MouseListener,ActionListener { boolean firstDraw = true; JFrame f; int x=0,y=0; public TestCanvas(JFrame jfr) { addMouseListener(this); f = jfr; } public void paint(Graphics g) { if(!firstDraw) { g.setColor(Color.red); g.drawLine(x+5,y+5,x+10,y+10); System.out.println("x: " + x + " y: " + y); } } //End of paint method public void repaint() { System.out.println("repaint"); }
public void draw(int x1, int y1) { x = x1; y = y1; paint(this.getGraphics().create()); } public void actionPerformed(ActionEvent ae) { this.setVisible(false); } public void mousePressed(MouseEvent e) { } public void mouseClicked(MouseEvent e) { Point cPPoint = SwingUtilities.convertPoint(this, e.getPoint(), f.getContentPane()); Component cmp = SwingUtilities.getDeepestComponentAt(f.getContentPane(),(int)cPPoint.getX(),(int)cPPoint.getY()); String cmpName = cmp.getName(); if(cmpName==null) { firstDraw = false; this.draw(e.getX(),e.getY()); String xx = e.getX() + ""; String yy = e.getY() + ""; //System.out.println("mouse event! " + xx + " " + yy ); } else { this.setVisible(false); } } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } } //End of HTMLCanvas class
Marco Schmidt - 13 Sep 2003 22:27 GMT fup2 comp.lang.java.programmer
Bryan R. Meyer:
>The code for the TestCanvas class is below. I suspect I have to save >the Graphics context. A Graphics context does not contain image data. But you can use one to draw into an image object. Some explanations at <http://www.geocities.com/marcoschmidt.geo/java-image-faq.html#savecomponent>.
Regards, Marco
 Signature Please reply in the newsgroup, not by email! Java programming tips: http://jiu.sourceforge.net/javatips.html Other Java pages: http://www.geocities.com/marcoschmidt.geo/java.html
Bryan R. Meyer - 14 Sep 2003 05:57 GMT Marco,
Thanks for the help. I understand how to draw to an image, but right now, that's not my problem. I have somewhat of a feel for what is happening though. When I set the glasspane to be visible and draw lines on it, none of the lines are erased. The lines accumulate which is what I want to happen. When I set the glasspane to be invisible and then set it back to be visible, the lines all disappear except the last one drawn. I'm assuming paint(Graphics g) is called again when I reset the glasspane to be visible. Since the x and y values for the line are global variables, they are remembered, but the calling of paint erases the glasspane and only draws the last line (based on the x and y values).
When I draw multiple lines and the JFrame containing the glasspane loses focus, the only lines that disappear are those where another window (such as an application window) has covered those particular lines. I am really confused as to how to solve the problem. The invocation of the paint is clearing the graphics. And I have no idea what is happening with the other problem. Any ideas on workarounds?
Thanks, Bryan
> fup2 comp.lang.java.programmer > [quoted text clipped - 9 lines] > Regards, > Marco Steve Claflin - 14 Sep 2003 15:21 GMT > Marco, > [quoted text clipped - 19 lines] > Thanks, > Bryan The first thing that happens when painting is that the area gets its background color painted (technically it is not erased, but if something covered the area, well, the background needs to get put back, too). Then your commands are executed. But the background color effectively wipes everything out. Then your paint instructions get called, which only draw one line. There are a few ways to solve this. One would be to create something like a Vector and save every line's info; then at paint time go back and redraw them all. Another would be to create an offscreen image, draw to that first, then just copy that to the onscreen image. The offscreen image will accumulate your lines.
Here's some code EXCERPTS from an example that draws boxes -- I've never tried it on a glass pane, though. As a side note, this example is not robust, because it doesn't handle things like the frame being resized.
public class Painter {
int x, y, w, h; Graphics g, gImage; Image i; PaintArea pa = new PaintArea();
//in constructor or other initializing method: g = pa.getGraphics(); i = pa.createImage(pa.getBounds().width, pa.getBounds().height); // resizing problems arise here gImage = i.getGraphics();
//the painted component class (which I did as an inner class):
private class PaintArea extends Panel implements ImageObserver { public void paint(Graphics g) {
gImage.setColor(c); gImage.fillRect(x, y, w, h); g.drawImage(i, 0, 0, this); } } }
 Signature Steve -- http://www.steveclaflin.com
Harald Hein - 14 Sep 2003 07:59 GMT > I am writing a program that puts HTML in a JEditorPane object > which is then placed in a JFrame object. I have a class (called > TestCanvas) which inherits from Canvas and which I use as the > glasspane for the JFrame. I didn't read any further, because you indicate that you mix lightweight (JEditorPane) and heavyweight (Canvas) components. This is not a good idea. You might want to fix that first (use a JComponent or JPanel instead of the Canvas).
Bryan R. Meyer - 15 Sep 2003 21:38 GMT Steve and Harald,
Thanks for the information. I do have one more question to ask. I am now able to accumulate my lines in the offscreen image. I was able to follow your example Steve and get it to work with the glasspane. My new problem is two-fold: a) the offscreen image background is gray and b) the color of my lines can not be set accordingly. If you look at my code below, I've attempted to set the color of the lines to be red in the paint(Graphics g) method, but instead they always show up as the color black. Any ideas as to why?
I suspect that to make the offscreen image transparent (like the glasspane itself) that I have to mess with the alpha values of the pixels. This seems rather expensive, but I've found no other solutions to make the background transparent. Is there a "cheap" way to do this? As always, thanks for the help.
-Bryan
class TestCanvas extends JComponent implements MouseListener,ActionListener,ImageObserver { boolean firstDraw = true; JFrame f; int x=0,y=0; Image img; public TestCanvas(JFrame jfr) { addMouseListener(this); f = jfr; } public void addNotify() { super.addNotify(); img = createImage(400,400); } public void paint(Graphics g) { if(!firstDraw) { img.getGraphics().setColor(Color.red); img.getGraphics().drawLine(x+5,y+5,x+10,y+10); g.drawImage(img, 0, 0, this); } } //End of paint method public void draw(int x1, int y1) { x = x1; y = y1; paint(this.getGraphics().create()); } public void actionPerformed(ActionEvent ae) { this.setVisible(false); } public void mousePressed(MouseEvent e) { } public void mouseClicked(MouseEvent e) { Point cPPoint = SwingUtilities.convertPoint(this, e.getPoint(), f.getContentPane()); Component cmp = SwingUtilities.getDeepestComponentAt(f.getContentPane(),(int)cPPoint.getX(),(int)cPPoint.getY()); String cmpName = cmp.getName(); if(cmpName==null) { firstDraw = false; this.draw(e.getX(),e.getY()); } else { this.setVisible(false); } } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } } //End of TestCanvas class
Bryan R. Meyer - 15 Sep 2003 21:56 GMT Alright, I figured out one problem and thought I would share. I can't do img.getGraphics().setColor(Color.red). I have to first get the image graphics then set the color like so:
Image img = createImage(400,400); Graphics imgG = img.getGraphics(); imgG.setColor(Color.red);
The problem with the transparent background remains. Anyone have any suggestions that would minimize the use of resources (i.e. I DON'T want to adjust the alpha values of all the background pixels.) and enable the offscreen image background to be transparent?
Thanks, Bryan
Steve Claflin - 15 Sep 2003 23:39 GMT > Alright, I figured out one problem and thought I would share. I can't > do img.getGraphics().setColor(Color.red). I have to first get the [quoted text clipped - 11 lines] > Thanks, > Bryan Yeah, I forgot about the glass pane issue. You need to create a BufferedImage instead of an Image, and use Graphics2D instead of Graphics, which you can do with:
Graphics2D gImage2d; BufferedImage bi;
then instead of createImage(400,400); and imgG.getGraphics():
bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR); gImage2d = bi.createGraphics(); gImage2d.setColor(new Color(0, 0, 0, 0)); // the last 0 is the alpha (opacity) gImage2d.fillRect(0, 0, width, height);
then to draw it:
gImage2d.setColor(Color.red); gImage2d.drawLine(x1, y1, x2, y2); g.drawImage(bi, 0, 0, this);
 Signature Steve -- http://www.steveclaflin.com
Bryan R. Meyer - 16 Sep 2003 00:20 GMT Problem solved.
You can use the GraphicsConfiguration class to make a transparent image using the createCompatibleImage method. It works great. Thanks guys for all your help!
Bryan
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|