Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > JComponent repaint nightmare

Reply
Thread Tools

JComponent repaint nightmare

 
 
Roger Davis
Guest
Posts: n/a
 
      11-22-2003
I am trying to draw a complicated image into an on-screen window
and make frequent, minor changes to that image, usually in
response to user input, e.g., draw a rubberband bounding box, etc.
I want to make these changes without having to completely
redraw the image , i.e., I want to redraw only the small part
of the image which has changed. Unfortunately every approach
I have tried results in failure -- when I try to redraw some
small part of my image, the unchanged (and un-redrawn) portion
of the image disappears from the display. I have been
stumbling lost through repaint() hell for three days now with
no end in sight, and am hoping that someone out there can
tell me how to do this. I am using Java 2 SE 1.4.2.

I am an X11 programmer who is new to Java, so I may be going
about this completely wrong, but here is what I am doing (based
largely on suggestions from various Java books). My drawing
object, called a Drawable, is an instantiation of my own direct
subclass of JComponent. This Drawable object is encapsulated in a
JScrollPane which has been stuffed into the content pane of a JFrame,
which also has a JMenuBar. I am doing my drawing into an off-screen
BufferedImage which I have allocated myself. Every time I perform
a drawing operation on this BufferedImage, e.g., adjusting a rubberband
bounding box, I create a Rectangle which bounds the affected area and
place it onto a queue, and call the JComponent.repaint() method. I
have overridden the JComponent.paint() method in my Drawable
class to examine this queue and transfer the appropriate subsections
of the BufferedImage into the Drawable. When my program starts
and creates the initial large, complicated image and transfers the
whole thing into the Drawable this works fine. What does *not*
work is when I subsequently redraw some small piece of the image
and then call repaint(), which forces a call to paint() -- when this
happens the entire contents of the on-screen Drawable are wiped out,
and all I see is my small updated area. Some agent external to my
Drawable's paint() method is clearing the Drawable before that
paint() method is called.

I tried overriding JComponent's update() method as suggested in
various books, but then found out that Swing does not even call
JComponent.update(), which I confirmed empirically by putting print
statements in my own overriding Drawable.update() method.

I then discovered documentation in various places which mention some
sneaky ComponentUI.update() method which may be clearing my JComponent.
However, Sun's Javadoc says that this should happen only if the
JComponent is opaque, and mine is not (at least according to isOpaque()
at the time of creation of the JComponent -- I have not explicitly set
it either way). Also, I've found other documentation that implies
that this does not happen anyway if you are working with your own
direct subclass of JComponent and have not explicitly created your
own UI delegate. (I *am* using my own direct subclass of JComponent and
I have *not* explicitly created any UI delegate. I don't even have a
clue of what a UI delegate is.)

After all of the above failed to get me anywhere, I scrapped the whole
BufferedImage approach and tried to use Swing's own double-buffering.
I have no idea if this is even possible and was not able to find any
programming examples, so I may have gone about it completely wrong,
but the bottom line is that failed also. I did a setDoubleBuffered()
on my JComponent and did all of my draws to the JComponent, then called
repaint(rect) after each drawing operation, where rect is the smallest
bounding Rectangle that contained the affected area. I did not override
JComponent.paint() in this attempt. This basically did the
same thing as my BufferedImage approach, only with a lot more flicker.

There has *got* to be a way to do this. I hope someone out there can
tell me how!

Thanks.

--
Roger Davis
University of Hawaii/SOEST
http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
 
 
 
Harald Hein
Guest
Posts: n/a
 
      11-22-2003
"Roger Davis" wrote:

> I am an X11 programmer who is new to Java,


Then I would ugently suggest that you get the Painting article from sun
and read it a few times.

http://java.sun.com/products/jfc/tsc...ing/index.html

Then I would suggest to continue with

http://java.sun.com/docs/books/tutor...ing/index.html

and

http://java.sun.com/docs/books/tutorial/2d/index.html

> largely on suggestions from various Java books).


It doesn't sound as if these books are too great.

> I am doing my drawing into an
> off-screen BufferedImage which I have allocated myself.


If you are only doing this for double buffering, this is not necessary.
Swing does double-buffering by itself. Consider changing your algorithm
so you don't need to buffer yourself. If you buffer yourself, turn at
least Swing's double-buffering off.

> I perform a drawing operation on this BufferedImage, e.g.,
> adjusting a rubberband bounding box,


Rubberbands etc. are maybe the only things where I would consider using
paintImmediately, instead of going through the repaint/update/paint
mechanism.

> I create a Rectangle which
> bounds the affected area and place it onto a queue,


Which queue? You just claimed you use a BufferedImage. Please post
complete, small example code. Code that can be compiled and runs as-is.

> and call the
> JComponent.repaint() method. I have overridden the
> JComponent.paint()


Override paintComponent(), not paint(). See the mentioned Painting
article.

> when
> this happens the entire contents of the on-screen Drawable are
> wiped out, and all I see is my small updated area.


Use a debugger. Pay special attention to what is going on in the
Superclass. You do call super.paint[Component](), don't you? You know
that the clip rectangle and origin can be different in calls to
paint[Component]()? Also use the debugger to check if and how much you
copy from your BufferedImage to the Graphics object. Again, check the
mentioned article.

> Some agent
> external to my Drawable's paint() method is clearing the Drawable
> before that paint() method is called.


There are no such agents. Yet again, learn more about the Swing/AWT
painting mechanism.

> I tried overriding JComponent's update() method as suggested in
> various books,


This is bullshit, because, as you have found out:

> Swing does not even call
> JComponent.update(), which I confirmed empirically by putting
> print statements in my own overriding Drawable.update() method.


You wouldn' have to, if you would have read the ...

Throw that book away.

> I then discovered documentation in various places which mention
> some sneaky ComponentUI.update() method which may be clearing my
> JComponent.


ComponentUI.update() is only called by the paintComponent() method, if
(a) there is a ui delegate, and (b) opaque is true.

JPanes has a ui delegate, and yes, it fills (not cleans) the background
with the background color, if opaque is true. JComponent doesn't have
one. opaque is all about filling.

If you overrider paintComponent(), you can decide for yourself what to
do. If your superclass has a ui delegate, you can use it by just
calling super.paintComponent() first in the method. If you don't have a
ui delegate, you better make sure that you satisfy the opaque flag
yourself.

However, since, you are buffering your own image, you can satisfy the
opaque flag by always at least copying as much data to the screen as
indicated via the clip region (now you know why I suggested to use a
debugger and check what's going on in the superclass and how the clip
region is set).

> I don't even have a clue of what a UI
> delegate is.)


Then get your ass up, and read about it.

> I did a setDoubleBuffered()


It is on by default.

> on my JComponent and did all of
> my draws to the JComponent,


Using getGraphics()? This will never work.

> There has *got* to be a way to do this. I hope someone out there
> can tell me how!


Stop whining, and start learning about the paint mechanism and how to
use a debugger.
 
Reply With Quote
 
 
 
 
Alex Hunsley
Guest
Posts: n/a
 
      12-11-2003
Roger Davis wrote:
[snip]
> I then discovered documentation in various places which mention some
> sneaky ComponentUI.update() method which may be clearing my JComponent.
> However, Sun's Javadoc says that this should happen only if the
> JComponent is opaque, and mine is not (at least according to isOpaque()
> at the time of creation of the JComponent -- I have not explicitly set
> it either way). Also, I've found other documentation that implies
> that this does not happen anyway if you are working with your own
> direct subclass of JComponent and have not explicitly created your
> own UI delegate. (I *am* using my own direct subclass of JComponent and
> I have *not* explicitly created any UI delegate. I don't even have a
> clue of what a UI delegate is.)


For starters, you should be doing your own painting in paintComponent,
and not paint (if that's what you're doing).
The update method, which you should leave well alone, calls paint, which
you should also leave well alone.
Paint calls paintComponent, paintBorder, and paintChildren. Hence, if
you override paintComponent in the right way, you should be ok.

If you don't call super.paintComponent(..) in your own paintComponent
method, swing won't do it's default blanking of the drawing area, which
is what it sounds like is happening.
You might also be interested in looking at Graphics.setClip if you want
to clip what gets drawn to a specific region.

I'm getting around, at last, to doing a web page about this very subject
(painting in swing + double buffering), I really need to finish it as it
sounds like it would be of help in your situation!


> After all of the above failed to get me anywhere, I scrapped the whole
> BufferedImage approach and tried to use Swing's own double-buffering.
> I have no idea if this is even possible and was not able to find any
> programming examples, so I may have gone about it completely wrong,
> but the bottom line is that failed also. I did a setDoubleBuffered()
> on my JComponent and did all of my draws to the JComponent, then called
> repaint(rect) after each drawing operation, where rect is the smallest
> bounding Rectangle that contained the affected area. I did not override
> JComponent.paint() in this attempt. This basically did the
> same thing as my BufferedImage approach, only with a lot more flicker.
>
> There has *got* to be a way to do this. I hope someone out there can
> tell me how!


Don't draw individual bits and then call repaint() after each bit. As
long as you override paintComponent, you can control what gets painted.
Call repaint() when you want to force paintComponent to get called.

I think doing your own double buffering sounds ideal in this situation.











 
Reply With Quote
 
Alex Hunsley
Guest
Posts: n/a
 
      12-11-2003
Roger Davis wrote:

> I am trying to draw a complicated image into an on-screen window
> and make frequent, minor changes to that image, usually in

[snip]

P.S. posting code would help a lot. If not to the group, to me, at
(E-Mail Removed) (remove the tooth from the email address to
get correct address).


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Best way to force a JComponent to repaint itself zerg Java 125 09-09-2008 01:14 AM
How to ensure a square JComponent? Jacob Java 8 03-18-2006 12:40 AM
JComponent on JTree smat Java 2 10-25-2005 04:34 AM
How to "ghost" a jcomponent? dbritton Java 2 02-05-2004 01:29 AM
Retarding the repainting of a JComponent Richard B. Christ Java 1 10-25-2003 01:50 AM



Advertisments