Glasspane and Saving Graphics

B

Bryan R. Meyer

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
 
B

Bryan R. Meyer

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
 
H

Harald Hein

Bryan R. Meyer said:
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).
 
S

Steve Claflin

Bryan R. Meyer said:
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);
}
}
}
 
B

Bryan R. Meyer

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
 
B

Bryan R. Meyer

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
 
S

Steve Claflin

Bryan R. Meyer said:
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);
 
B

Bryan R. Meyer

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top