Glasspane and Saving Graphics

Discussion in 'Java' started by Bryan R. Meyer, Sep 13, 2003.

  1. 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
     
    Bryan R. Meyer, Sep 13, 2003
    #1
    1. Advertising

  2. 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
    --
    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
     
    Marco Schmidt, Sep 13, 2003
    #2
    1. Advertising

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




    Marco Schmidt <> wrote in message news:<>...
    > 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
     
    Bryan R. Meyer, Sep 14, 2003
    #3
  4. Bryan R. Meyer

    Harald Hein Guest

    "Bryan R. Meyer" wrote:

    > 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).
     
    Harald Hein, Sep 14, 2003
    #4
  5. "Bryan R. Meyer" wrote:
    >
    > 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


    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);
    }
    }
    }


    --
    Steve
    --
    http://www.steveclaflin.com
     
    Steve Claflin, Sep 14, 2003
    #5
  6. 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, Sep 15, 2003
    #6
  7. 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
     
    Bryan R. Meyer, Sep 15, 2003
    #7
  8. "Bryan R. Meyer" wrote:
    >
    > 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


    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);


    --
    Steve
    --
    http://www.steveclaflin.com
     
    Steve Claflin, Sep 15, 2003
    #8
  9. 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
     
    Bryan R. Meyer, Sep 16, 2003
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Kandell
    Replies:
    4
    Views:
    4,188
    eeebop
    Dec 10, 2004
  2. Wolfgang
    Replies:
    1
    Views:
    1,123
  3. Replies:
    6
    Views:
    439
  4. Dick Moores

    Saving output of Turtle Graphics?

    Dick Moores, Apr 7, 2007, in forum: Python
    Replies:
    7
    Views:
    435
    Dick Moores
    Apr 7, 2007
  5. Icarus
    Replies:
    5
    Views:
    594
    Icarus
    Aug 3, 2008
Loading...

Share This Page