Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / First Aid / September 2003

Tip: Looking for answers? Try searching our database.

Glasspane and Saving Graphics

Thread view: 
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 Magazines

Get 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 ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.