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 / First Aid / August 2005

Tip: Looking for answers? Try searching our database.

Waiting for user input in a GUI

Thread view: 
Michal Brzozowski - 31 Jul 2005 12:24 GMT
Hello,
I have the following problem:

I have a class that holds some data, and I want
the constructor to create a window and let the
user supply the data.

The problem is that the constructor creates the
GUI and exits, and data from the user arrives
when the object is already created.  I tried
doing something like

while (data_is_null) Thread.sleep(100);

and the end of the constructor.

This worked fine, but when I tried creating
the object from another window, the GUI in the
constructor didn't show up, only the frame.

Now I know the solution would probably be using
invokeLater, or invokeAndWait, but I can't figure
it out.

Some help (maybe with pseudocode) would be really
nice.

Michal Brzozowski

ps.: my bigger problem is that I actually don't
understand how Swing is using threads.
Andreas Koch - 31 Jul 2005 13:26 GMT
> Hello,
> I have the following problem:
[quoted text clipped - 7 lines]
> when the object is already created.  I tried
> doing something like

I'm not yet deep in java, but from general
programming i'd say you could try a more event
based solution :

1. create the GUI and go back to idle
2. When the user filled out the data and clicked
"OK", let the GUI create the object
3. let the GUI do a callback to the main app
Andrew Thompson - 31 Jul 2005 13:39 GMT
> I have a class that holds some data, and I want
> the constructor to create a window ..
(..and wait)

Is that Window (AWT) or JWindow (Swing)?

Make it a *modal* (J)Dialog or a JOptionPane
and you problems will be solved.

Signature

Andrew Thompson
physci.org 1point1c.org javasaver.com lensescapes.com athompson.info
Dancing Space Potatoes?  You Bet!

Thomas Hawtin - 31 Jul 2005 16:44 GMT
>>I have a class that holds some data, and I want
>>the constructor to create a window ..
[quoted text clipped - 5 lines]
> Make it a *modal* (J)Dialog or a JOptionPane
> and you problems will be solved.

And you'll end up with a highly user hostile application.

The way to go about it is something like:

private void somethingLong(String arg) {
    assert EventQueue.isDispatchThread(); // In EDT
    Thread thread = new Thread(new Runnable() {
            public void run() {
                // Outside EDT
                String result;
                try {
                    Thread.sleep(3000);
                    result = "done: ";
                } catch (java.lang.InterruptedException exc) {
                    result = "punt: ";
                }
                setStatusLater(result+arg);
            }
    }), "Something long");
    thread.setPriority(Thread.NORM_PRIORITY); // 1 less than EDT
    thread.setDaemon(true);
    thread.start();
}
private void setStatus(String message) {
    assert !EventQueue.isDispatchThread(); // Outside EDT
    // If we call this repeatedly the GUI wont have a fit.
    synchronized (this) {
        statusMessage = message;
    }
    EventQueue.invokeLater(new Runnable() {
            public void run() {
                // In EDT
                final String statusMessage;
                synchronized (this) {
                    statusMessage = this.statusMessage;
                }
                statusLabel.setText(statusMessage);
            }
    });
}

You can do better by using the thread pooling of java.util.concurrent,
but that's a bit advanced and makes little difference. Also you can see
if you've already fired off an invokeLater before queueing up more to do
the same. Sometimes callbacks should be throttled - no point in updating
the status for every single line of file read, but it should be up to
date. There's also SwingWorker in Java SE 6.0 and on dev.java.net which
suits some people.

Tom Hawtin
Signature

Unemployed English Java programmer
http://jroller.com/page/tackline/

Michal Brzozowski - 01 Aug 2005 09:14 GMT
[..]

> And you'll end up with a highly user hostile application.

I used this approach and it looks real nice.  What I was
trying to do before was the exact same thing, I just didn't
realize that there's already a class for that.

> The way to go about it is something like:

snip code

Can you please explain your code a bit?  I don't understand
what it does and how it solves the problem...
Thomas Hawtin - 01 Aug 2005 15:37 GMT
> [..]
>
[quoted text clipped - 3 lines]
> trying to do before was the exact same thing, I just didn't
> realize that there's already a class for that.

The trouble is that you lock up the rest of your world whilst a single
window appears. Not something you want to do if your aim is maintain any
kind of usability. There is no point in writing such applications.

> Can you please explain your code a bit?  I don't understand
> what it does and how it solves the problem...

This is a GUI centric way of doing things. Slightly different from what
you described, which I'll explain at the bottom (if I remember...).

We assume this is called from some GUI event handler. All GUI
processing, including event handlers, should be done in the same thread
known as the Event Dispatch Thread (EDT). We put in asserts both to
remind the programmer from which thread it should be called, and to
check that we are doing it right.

The goal is to put the long running tasks outside of the EDT so the GUI
doesn't freeze. Long running task may be computational or involve
network connections.

> private void somethingLong(String arg) {
>     assert EventQueue.isDispatchThread(); // In EDT

This just sets up and runs our task that should run in response to the
event.

>     Thread thread = new Thread(new Runnable() {
>             public void run() {
[quoted text clipped - 7 lines]
>                 }
>                 setStatusLater(result+arg);

This last call is to push the results back to the GUI.

>             }
>     }), "Something long");
>     thread.setPriority(Thread.NORM_PRIORITY); // 1 less than EDT
>     thread.setDaemon(true);
>     thread.start();

That's off and running. We almost instanteously return to the GUI, so
that it feels responsive.

> }
> private void setStatus(String message) {
>     assert !EventQueue.isDispatchThread(); // Outside EDT

This method is going to reflect changes from our non-GUI task into our
GUI. In this case it's just changing a status message, but could do
something more complicated involving more data.

>     // If we call this repeatedly the GUI wont have a fit.
>     synchronized (this) {
>         statusMessage = message;
>     }

Both our task thread and EDT are going to access the statusMessage
variable, so it needs to be synchronised. Here we update it for the next
update GUI task to update the actual GUI component.

>     EventQueue.invokeLater(new Runnable() {
>             public void run() {
[quoted text clipped - 4 lines]
>                 }
>                 statusLabel.setText(statusMessage);

This code will run in the EDT sometime later and do the GUI updating. We
could have used a final variable from the enclosing method rather than
the synchronised member variable. However this has the advantage that if
I was updating progress, say, then if the non-GUI thread did thousands
of updates while the EDT was busy, then only the last update does any
real GUI work. Otherwise we'd have the GUI revalidating and repainting
itself for each of the thousands of out of date states.

>             }
>     });
> }

I think the original problem was phrased to imply a solution where there
would be another main thread running the show. This is how DOS programs
tended to work. It doesn't make a great fit for GUIs. You can do it, but
in order not to compromise usability takes some effort. With more than
one GUI component where is your thread going to be waiting? It all gets
very complicated.

Tom Hawtin
Signature

Unemployed English Java programmer
http://jroller.com/page/tackline/



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.