Link to home
Start Free TrialLog in
Avatar of Sasha_Mapa
Sasha_Mapa

asked on

update(getGraphics()) vs. repaint()

I have seen top experts (espesially heyhey_) saying many times never to use getGraphics() to paint. I am having a small problem with my current application and I think the easiest way to solve it would be the following portion of code:

Graphics g = myComponent.getGraphics();
if (g!=null)
  g.update(g);

but respecting their opinion I would like an explanation on why I shouldn't use it.
The problem with repaint() occurs when for example I have a long and costly (takes a lot of CPU time) process that needs to inform a progress bar about its progress. If I update the value of the progress bar and call repaint() it will only end up repainting after the process is over and so the progress bar becomes useless. Calling update(getGraphics()) seems like the easiest and clearest way out of this.
Avatar of adam923
adam923

don't you mean
myComponent.update(g);
?

how about calling
myComponent.repaint(1000);
So it will redraw within 1 sec.  From the api for java.awt.Component...
Repaints the component. This will result in a call to update within tm milliseconds.
You can use update if you know what you are doing. This is because the repaint() by default will paint in 100 milliseconds. So, if you called repaint() too many time within 100 milliseconds, only one will be executed while the rest of the calls will be discarded. repaint() basically manage paint() method for you. If you are sure that you will halt the system by too many update() or paint() call, then you can go ahead using it.
you'd better start two Threads - one that execute your 'long and costly process' inside another thread and another (with max priority) that will call repaint every 100 millis (I've used this technique to render a progress bar while the Netscape is loading Swing classes from the local Classpath - almost 20 - 30 seconds).

if this solution does not work for you, I'd like to see your code :)
heyhey_: doesn't that have a negative impact on the total time that the task takes? (nice alliteration?)
btw. I've used paint(getGraphics()) only once ...
I have a panel which is playing some nice animation, but when I show java.awt.PopupMenu on that Panel - the Panel stops repainting (another thread is recalculating the animation stuff) ... I had to start another special  Thread which calls paint(getGraphics()) every 100 millis (repain() doesn't work in such case) ... the other problem was that there is no way to find when the PopupMenu disappears ...

the most irritating bug in the world of Java that I've ever seen :(
>  doesn't that have a negative impact

well - the second Thread just calls repaint() every 100 millis - you'd better use differnet Thread, because some operations inside the first thread may be out of your control (for example some method call may take 30 seconds / 100% CPU to finish)
Avatar of Sasha_Mapa

ASKER

mikemhc and adam: AFAIK, the repaint(long) method is for asking the system to paint it after a certain delay, i.e. NOT calling it in the given time period. If you look at the AWT sources, you will find out that repaint() calls repaint(0). The documentation got me confused at first too, they made a bad choice of words :(

heyhey: How would calling repaint in another thread help? And how would that be different from calling repaint from that same thread? all repaint() is supposed to do is ask the system to call update(Graphics) sometime and return immediately, so why does it matter what thread asks it to repaint? Even if it does have max priority...
I suspect that the reason for not repainting while doing that costly process is that the processor is all taken up by that process and the system can't "squeeze" in an update(Graphics) call.
yes adam, I did mean myComponent.update(g) :-)
can you post some code ?

after all if update(getGraphics()) works for you - use it :) - I am biased against getGraphics(), but I'll use it if it's the only possible solution ...
sasha i thing you are interpreting the wording incorrectly repaint(long x) is said to guarantee that the repaint happens within that time frame, not after that time frame... therefore it is still correct that repaint() == repaint(0) but that means do it right away, not do it after 0 millis
>> is said to guarantee

there's no guarantee


- Class java.awt.Component -

public void repaint()

Repaints this component.

This method causes a call to this component's update method as soon as possible.

wrong method, read the api for repaint(long l)
no guarantee :)

try some code instead reading the API :) (as soon as possible is your best guess :)
adam, I was confused when I saw that documentation too. The fact is that it is the way I explained it... repaint(long) asks to repaint AFTER the given amount of time, repaint() asks to repaint right away, but the system will call update(Graphics) as soon as possible ALWAYS, you can't force it to call update(Graphics) at any given time.

heyhey, generally my code looks like this (actually, it's different from the case I described, but in that case it doesn't work either):

public class Map{

  ...

  public boolean mouseMove(Event evt, int x, int y){

    for (int i=0;i<mapObjects.size();i++){
       MapObject mapObject = (MapObject)(mapObjects.elementAt(i));
       if (mapObject.contains(x,y)){
         currentMapObject = mapObject;
         return false;
       }
    }
    currentMapObject = null;
    return false;
  }

  ...

}

and the Container that holds the map defines this:

public class MyApplet extends Applet{

  public void mouseMove(Event evt, int x, int y){
    if (myMap.getCurrentMapObject()==null)
      myLabel.setText("");
    else
      myLabel.setText(myMap.getCurrentMapObject().getName());
    return true;
  }

}


The problem is that if I move the mouse constantly over the map, the label doesn't get updated at all, it only gets updated when I stop moving the mouse.

Umm, actually I see that this is very different from what I said because only god knows when the parent's mouseMove method will get called...
Any ideas how to fix this? maybe directly call getParent.mouseMove(evt,x,y) from the child's mouseMove?







}
I had similiar project and I used my own 'pseudo-component hiearcy' - ONE awt.component that renders inside itself all the other 'components' and listens for mouse moves - when the user moves the mouse over some  'pseudo-component' it will set it's rollover flag and call repaint - and everything worked quite well.

btw. the code that you posted does not use repaint() at all :)

If I have a small number of map objects it works fine. When I have a lot of "objects", finding the one the mouse is over becomes expensive and what I am guessing is that the next mouse move event is already queued by the time the mouseMove method returns, and that doesn't leave enough time for the update(Graphics) call...

When you do myLabel.setText(String) the label calls repaint on itself (it's a custom label, I implemented it myself :-) ).
ASKER CERTIFIED SOLUTION
Avatar of heyhey_
heyhey_

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Yes, I am using a heavyweight Label, why wouldn't lightweight work?
call it bias. no logical explanation.