Hi chaps, wonder if anyone can suggest a solution to this problem I'm having
with the GUI in my app.
I have one view, let's call it CityView (as this is it's name). Two
functions are important: One is the SelectCity() function, which reads a
database and determines what is going to be shown. This function can take a
good couple of seconds to run. The other is the CityView.paint() function
which renders the view, using the data from CityView.SelectCity().
The problem is that CityView.paint() is often called by the system when
CityView.SelectCity() is halfway through running, thus rendering only half
the data.
How can I prevent this from happening? I have tried using
this.setIgnoreRepaint() which didn't work, and I've tried using wait() in
paint() and notify() in SelectCity(), and this worked - but sometimes led
to deadlock (caused when SelectCity() added a JPanel which appears to call
paint(), which is wait()-ing for SelectCity() to finish).
Any ideas? Thanks,
Jim
Steve W. Jackson - 04 Jan 2007 16:04 GMT
> Hi chaps, wonder if anyone can suggest a solution to this problem I'm having
> with the GUI in my app.
[quoted text clipped - 17 lines]
> Any ideas? Thanks,
> Jim
I'll briefly offer a suggestion of the conventions, which recommend that
your "functions" (actually methods) should not begin with upper case
names...
Gathering from this that the GUI is Swing, since you refer to a JPanel,
<http://java.sun.com/products/jfc/tsc/articles/painting/index.html#swing>
is a good article to see on how Swing painting works. One point from
there is that you should not call paint() at all -- the system calls
that when needed, as you've discovered. Instead, you should override
paintComponent() and do your rendering there.
Since your component's contents are currently being rendered on request,
I'll recommend that you consider changing your design so that what's
actually rendered when this happens is an off-screen image, perhaps in a
BufferedImage. When your selectCity code executes, it would then draw
this buffer and call repaint() on the panel. When paint() is invoked by
the system (whether in response to your repaint request or some other
action outside your direct control), such that it ends up calling your
panel's paintComponent() method, what gets rendered on the panel is this
buffer.
This isn't as complex as it might sound -- if I can figure it out, being
pretty much graphically challenged, pretty much anyone can. :-)
= Steve =

Signature
Steve W. Jackson
Montgomery, Alabama
Jim - 04 Jan 2007 17:27 GMT
[snip]
Hmm, good answer. You may have guessed I come from a C++ background and am
fairly new to java. Hence the lack of adherence to conventions. :)
SelectCity() doesn't actually do any drawing - it reads the database and
decides what should be drawn, although it does add/remove components and
such.
I don't ever call paint() directly. I have overloaded it (is this the java
term?) to do the actual drawing.
I really like your idea of drawing to an off-screen buffer. So you suggest
that SelectCity() should read the data AND draw it to a buffer, and the
overloaded paint func^H^H^H^H method should merely paint the buffered image
to the screen. Yeah, I can see the logic in that.
Thanks mate.
Jim
Steve W. Jackson - 04 Jan 2007 18:15 GMT
> [snip]
>
[quoted text clipped - 15 lines]
> Thanks mate.
> Jim
My preferred environment before Java was C, so I too had the long
ingrained habit of saying "function" instead of "method." I never did
much C++, so I don't know whether the OO aspect would've caused any
shift or not. :-)
I may have misread the original post and simply *assumed* that your
SelectCity code was drawing. On re-reading, I see that you said only
that it determines what was to be displayed and that paint() "renders
the view". Apologies if I misinterpreted.
But the off-screen buffer concept that I described is what we use in our
application, and I've learned a great deal about its advantage over the
time I've been working with it. Ours is a modeling and simulation
application that maintains its "model" in an XML document. As user
actions and other things occur, they result in the firing of property
change events that cause the BufferedImage to get redrawn. Any time
that buffer gets changed, the code that does so will also invoke
repaint() on the corresponding JPanel. When the system determines a
need to paint that same panel, it ultimately does the same. The result
is that the paintComponent code does little more than simply draw
whatever is currently in the BufferedImage onto the Graphics object
which is provided as a parameter to the paintComponent method.
Hope I was able to help.
= Steve =

Signature
Steve W. Jackson
Montgomery, Alabama
Nigel Wade - 05 Jan 2007 10:16 GMT
> [snip]
>
[quoted text clipped - 4 lines]
> decides what should be drawn, although it does add/remove components and
> such.
This has very serious implications. If your SelectCity() method adds/removes
components from the GUI then it *must* be running in the event dispatch thread.
If it isn't the consequences can be quite dramatic. For reasons see the Java
tutorial on Swing. But imagine the scenario where the EDT is re-drawing the
screen at the same time as the code in your thread is adding/removing
components? Chaos results. Also, if you add/remove components from outside the
EDT then the EDT doesn't know it needs to update the screen so you likely won't
see them being added/removed until the next time the EDT decides it needs to
update the screen for some other reason.
However, you say that SelectCity() may take a few seconds to run, so this would
normally preclude running in the EDT because the entire GUI would be blocked
while this task was performed. So you have a dilemma, you have actions which
dictate execution within the EDT, but a time constraint which dictates
otherwise.
You can get around this by using the SwingUtilities.invokeLater() method, and
move the code which adds/removes components into a Runnable which is passed to
invokeLater().

Signature
Nigel Wade, System Administrator, Space Plasma Physics Group,
University of Leicester, Leicester, LE1 7RH, UK
E-mail : nmw@ion.le.ac.uk
Phone : +44 (0)116 2523548, Fax : +44 (0)116 2523555
Andre Hinrichs - 04 Jan 2007 16:28 GMT
> Hi chaps, wonder if anyone can suggest a solution to this problem I'm
> having with the GUI in my app.
[quoted text clipped - 18 lines]
> Any ideas? Thanks,
> Jim
I would suggest to implement a semaphore:
private java.util.concurrent.Semaphore semaphore;
CityView() {
semaphore = new java.util.concurrent.Semaphore(1);
}
SelectCity() {
try {
semaphore.acquire();
} catch ( InterruptedException ignore ) {}
/* do here what you want to do... */
semaphore.release();
}
paint() {
try {
semaphore.acquire();
} catch ( InterruptedException ignore ) {}
/* do here what you want to do... */
semaphore.release();
}