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 / GUI / February 2004

Tip: Looking for answers? Try searching our database.

Using JComponent.getGraphics() in Swing for incremental painting

Thread view: 
Michael Carrato - 13 Feb 2004 07:47 GMT
Hello,

I have read many posts and articles saying "don't ever use
getGraphics() in Swing JComponents... always use paintComponent()!" I
understand the motivation for such statements: the paintComponent()
method should be used to implement painting, in order to ensure
correct behavior in all situations.

However, my question is: is it OK, from within an event handler, to
paint using getGraphics() PURELY AS AN OPTIMIZATION, AS LONG AS
paintComponent() does the right thing?

An example:

class MyComponent extends JComponent
{
 ArrayList thingsToPaint=new ArrayList();
 public void mySwingEventHandler(SomeEvent e)
 {
   //update thingsToPaint so that paintComponent
   //works correctly
   thingsToPaint.add(somethingNewToPaint);
   //try painting directly
   Graphics g = getGraphics();
   if(g != null)
   {
      //we have a graphics, so paint the new
      //thing directly.
      somethingNewToPaint.drawOn(g);
      g.dispose();
   }
   else
   {
      //No graphics object available... so just
      //call repaint().
      repaint();
   }
 }
 public void paintComponent(Graphics g)
 {
   //paint everything
   int i, size = thingsToPaint.size();
   for(i=0; i < size; ++i)
   {
     ((ThingToPaint) thingsToPaint.get(i)).drawOn(g);
   }
 }    
};

I actually have a good reason for doing this. I am writing a simple
image manipulation program, and I need to implement a rectanglar
selection facility. In order to accomplish this, I need to listen to
mouseDragged events and repaint the rectangle on the image at each new
position. Swing forces you to re-paint the entire image each time
(i.e. no incremental updates), which is annoyingly slow for this
particular problem. And I don't want to turn off double buffering.

If I use getGraphics() directly (as in the example above), I can just
update a tiny section of the image, and it is blindingly fast and
smooth. I have tested this, and it works wonderfully in my limited
tests. But I don't want to do it if it will be problematic down the
line.

So, is it OK to use getGraphics() if the full repainting functionality
is available in paintComponent()? Or is there some other reason not to
use getGraphics()?

Thanks,

Mike Carrato
Thomas Weidenfeller - 13 Feb 2004 08:37 GMT
> However, my question is: is it OK, from within an event handler, to
> paint using getGraphics() PURELY AS AN OPTIMIZATION, AS LONG AS
> paintComponent() does the right thing?

In general, you already have everything for painting this new part in
paintComponent(), so why duplicate code?

In your case, where you have a need for immediate action (e.g. when you
handle some cross-hair cursor, selection or some interactive resizing),
have a look at paintImmediately().

If you would have added just another shape, etc. to the drawing,
consider just calling repaint() with the affected region as parameter.
Especially if you have no need for immediate feedback.

In both cases consider to make sure that you observe the cliping area
inside paintComponent(), so you don't paint more than necessary.
Observing the cliping region might be a much better optimization if you
have many things to paint, and if you have managed to organize them in a
data structure which allows for efficient spatial separation. Otherwise
Swing  will have to do the cliping for each item individually. If you
don't have many things to paint, you can leave the entire cliping to
Swing, it isn't too bad at it.

/Thomas
Michael Carrato - 16 Feb 2004 15:23 GMT
> > However, my question is: is it OK, from within an event handler, to
> > paint using getGraphics() PURELY AS AN OPTIMIZATION, AS LONG AS
[quoted text clipped - 5 lines]
> handle some cross-hair cursor, selection or some interactive resizing),
> have a look at paintImmediately().

I didn't realize that paintImmediately() can be called with a
rectangle. I've since tried that, and performance is surprisingly
good. Swing does a really nice job of optimizing painting, even within
a single component.

So now I'm sold on paintImmediately(), but I still would like to
suppress the double buffering overhead, if possible. Double buffering
causes the entire screen image to be copied into the offscreen image
buffer, and for something as interactive as this I'd like to do as
little redrawing as possible.

Can I de-activate double buffering temporarily while calling
paintImmediately(), then re-activate it after I'm done?

> If you would have added just another shape, etc. to the drawing,
> consider just calling repaint() with the affected region as parameter.
> Especially if you have no need for immediate feedback.

Yes, there is a need for immediate feedback. It's a rectangular region
selector, so each mouse movement event requires a repaint of the
selection rectangle.

> In both cases consider to make sure that you observe the cliping area
> inside paintComponent(), so you don't paint more than necessary.
[quoted text clipped - 4 lines]
> don't have many things to paint, you can leave the entire cliping to
> Swing, it isn't too bad at it.

These are all great tips. Thank you for your time.


> /Thomas

Mike Carrato
ak - 16 Feb 2004 16:15 GMT
> Can I de-activate double buffering temporarily while calling
> paintImmediately(), then re-activate it after I'm done?

JComponent#setDoubleBuffered(true);

--

____________

http://reader.imagero.com the best java image reader.
Michael Carrato - 17 Feb 2004 15:35 GMT
> > Can I de-activate double buffering temporarily while calling
> > paintImmediately(), then re-activate it after I'm done?
> >
> JComponent#setDoubleBuffered(true);

Yes, but:
(1) Can I switch just before paintImmediately() and switch back just
after?
(2) Do I call setDoubleBuffered? on the JComponent itself, or do I
need to call it on the enclosing frame?

Mike
Thomas Weidenfeller - 17 Feb 2004 15:55 GMT
> Yes, but:
>  (1) Can I switch just before paintImmediately() and switch back just
> after?
>  (2) Do I call setDoubleBuffered? on the JComponent itself, or do I
> need to call it on the enclosing frame?

http://java.sun.com/products/jfc/tsc/articles/painting/index.html#db

and

http://java.sun.com/products/jfc/tsc/articles/painting/index.html#paint_process

should get you started.

/Thomas
Michael Carrato - 17 Feb 2004 21:21 GMT
> > Yes, but:
> >  (1) Can I switch just before paintImmediately() and switch back just
[quoted text clipped - 11 lines]
>
> /Thomas

Thanks for the links. I had read this article a few days ago, but I
was still stuck on the getGraphics()-based solution, so I forgot about
it.

So, based on everything I've read, I am planning to try the following
in my event handler:

 boolean isDB =
    theJComponent.getRootPane().isDoubleBuffered();
 //turn off double buffering, temporarily
 theJComponent.getRootPane().setDoubleBuffered(false);
 paintImmediately(...);
 //restore the original buffering setting.
 theJComponent.getRootPane().setDoubleBuffered(isDB);

Thanks again for your help.

Mike Carrato


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.