paintComponent into a BuffereImage?  
Author Message
fiziwig





PostPosted: 2006-8-10 6:27:00 Top

java-programmer, paintComponent into a BuffereImage? It seems like I should be able to override the paintComponent method of
a class and have it do its paint into a BufferedImage something like
this:

public void paintComponent(Graphics g) {

BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2D = image.createGraphics();
super.paintComponent( g2D );

.. etc ...

But all I get is a null pointer exception on super.paintComponent( g2D
); even though g2D is definitely NOT null. The exception actually comes
deep in the bowels of Java at:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at java.awt.Rectangle.intersects(Unknown Source)
at javax.swing.text.BoxView.paint(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI$RootView.paint(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.paintSafely(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.paint(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at TextPanel.paintComponent(TestClass.java:139) <--- the
super.paintComonent()

Any ideas on how to make this work?

Thanks,

--gary

 
Thomas Fritsch





PostPosted: 2006-8-10 8:15:00 Top

java-programmer >> paintComponent into a BuffereImage? fiziwig" <email***@***.com> wrote:
> It seems like I should be able to override the paintComponent method of
> a class and have it do its paint into a BufferedImage something like
> this:
>
> public void paintComponent(Graphics g) {
>
> BufferedImage image = new BufferedImage(width, height,
> BufferedImage.TYPE_INT_RGB);
> Graphics2D g2D = image.createGraphics();
> super.paintComponent( g2D );
>
> .. etc ...
Be aware that paintComponent() may be called hundreds of times per second,
depending on what you do with your GUI (moving it, maximizing it, resizing
it, ...). It is therefore not a good idea to create a new BufferedImage each
time, and paint on it.
>
> But all I get is a null pointer exception on super.paintComponent( g2D
> ); even though g2D is definitely NOT null.
Correct.
> The exception actually comes deep in the bowels of Java at:
>
> Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
> at java.awt.Rectangle.intersects(Unknown Source)
The NullPointerException occurs inside Rectangle's method
intersects(Rectangle rect) probably because the rect passed in is null. You
may want to look into Sun's source 'Rectangle.java' (you'll find it in
'src.zip' which is part of the JDK installation).
> at javax.swing.text.BoxView.paint(Unknown Source)
> at javax.swing.plaf.basic.BasicTextUI$RootView.paint(Unknown Source)
> at javax.swing.plaf.basic.BasicTextUI.paintSafely(Unknown Source)
> at javax.swing.plaf.basic.BasicTextUI.paint(Unknown Source)
> at javax.swing.plaf.basic.BasicTextUI.update(Unknown Source)
> at javax.swing.JComponent.paintComponent(Unknown Source)
> at TextPanel.paintComponent(TestClass.java:139) <--- the
> super.paintComonent()
>
> Any ideas on how to make this work?
I don't know what exactly you want to achieve. I assume you are just curious
and want to grab a snapshot of your TextPanel, to see if it works.
Don't override paintComponent(), but call paint() directly once after your
panel has got visible:
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2D = image.createGraphics();
yourTextPanel.paint(g2D);
You don't call paintComponent(), but call paint(), because that will draw
the whole component (including its border, its children, and the component
itself). You may want to look into the source 'JComponent.java', to see what
paint() actually does.

--
Thomas


 
fiziwig





PostPosted: 2006-8-11 0:45:00 Top

java-programmer >> paintComponent into a BuffereImage?
Thomas Fritsch wrote:
> fiziwig" <email***@***.com> wrote:
> > It seems like I should be able to override the paintComponent method of
> > a class and have it do its paint into a BufferedImage something like

<snip>

> Be aware that paintComponent() may be called hundreds of times per second,
> depending on what you do with your GUI (moving it, maximizing it, resizing
> it, ...). It is therefore not a good idea to create a new BufferedImage each
> time, and paint on it.
> >

<snip>

> >
> > Any ideas on how to make this work?
> I don't know what exactly you want to achieve. I assume you are just curious
> and want to grab a snapshot of your TextPanel, to see if it works.

<snip>

> --
> Thomas

Thanks for that warning about the frequency of paintComponent(). That
will obviously not be satisfactory.

My purpose is that, out of desperation, I'm trying everything possible
to rotate a JTextPane by 90 or 180 degrees. I've tried at least two
dozen different ways to do it. The most straightforward way, to apply
an AffineTransform to the JTextPane simply doesn't work correctly, even
though it DOES work on other components such as JLabels, etc. On the
JTextPane the text rotates, but the clipping is all messed up and I
haven't found any way to get it to work correctly.

All I want to do is to display the contents of a JTextPane, in
non-editing mode, rotated 90 or 180 degrees, and as far as I can tell,
Java just isn't capable of doing that. Either that or the JTextPane +
AffineTransform combination has some serious unfixed bugs.

I can't use a JLabel (which I CAN rotate) because I need the text to
retain its attributes like font, bold, size, etc. and a JLabel can't do
that.

Any ideas?

--gary

 
 
fiziwig





PostPosted: 2006-8-11 4:50:00 Top

java-programmer >> paintComponent into a BuffereImage?
Thomas Fritsch wrote:
> fiziwig" <email***@***.com> wrote:
> > It seems like I should be able to override the paintComponent method of
> > a class and have it do its paint into a BufferedImage something like
> > this:
> >
> > public void paintComponent(Graphics g) {
> >
> > BufferedImage image = new BufferedImage(width, height,
> > BufferedImage.TYPE_INT_RGB);
> > Graphics2D g2D = image.createGraphics();
> > super.paintComponent( g2D );
> >
> > .. etc ...
> Be aware that paintComponent() may be called hundreds of times per second,
> depending on what you do with your GUI (moving it, maximizing it, resizing
> it, ...). It is therefore not a good idea to create a new BufferedImage each
> time, and paint on it.

FWIW: I solved the problem like this:

class TextPanel extends JTextPane {

// implements rotation for a JTextPane

private int rotation;
private int tx, ty;
private int wide, high;
private BufferedImage renderedText = null;

// valid rotation values are:
// 0 = no rotation
// 1 = rotation 90 degree clockwise
// 2 = rotation 180 degrees
// 3 = rotation 90 degrees counterclockwise

TextPanel() {
super();
rotation = 0;
tx = 0;
ty = 0;
}
public void setDefaultBounds( int x, int y, int width, int height)
{
high = height;
wide = width;
super.setBounds(x,y,width,height);
}
public void setRotation( int newRotation ) {

newRotation = newRotation % 4;
if ( rotation != newRotation ) {
switch (newRotation) {
case 0 : tx = 0; ty = 0; break;
case 1 : tx = 1; ty = 0; break;
case 2 : tx = 1; ty = 1; break;
case 3 : tx = 0; ty = 1; break;
}
if ( newRotation != 0 ) {
if ( renderedText==null) {
rotation = 0; // so that text is actually rendered
renderedText = new BufferedImage(wide, high,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2D = renderedText.createGraphics();
paint( g2D );
}
}
rotation = newRotation; // so the repaint will paint the
rendered image
if ((rotation%2)==0) {
setSize(wide,high);
} else {
setSize(high,wide);
}

repaint();
}
}
public int getRotation() { return rotation; }

public void paintComponent(Graphics g) {

if ( rotation == 0 ) {
super.paintComponent(g);
return;
}
Graphics2D g2 = (Graphics2D) g;
double angle = rotation * Math.PI/2;
AffineTransform tr = g2.getTransform();
if (rotation==2) {
tr.setToTranslation(wide*tx,high*ty);
} else {
tr.setToTranslation(high*tx,wide*ty);
}
tr.rotate(angle);
g2.drawImage(renderedText, tr, this);
}
}

--gary