Code structure in a GUI swing multihreaded application

319 Views Asked by At

I'm new to Java and threads in general and I have a following GUI application in java:

  1. In a frame, a user clicks mouse anywhere and an image appears.

  2. Once image appears, a real-time timer starts running, updating itself in a jLabel Depending on values that user chose on the gui, that timer can go up to 5 seconds.

  3. At the same time a sound clip is played. if image and sound match, user clicks and thus stops the timer. A couple of jLabel values are updated to reflect a match or a miss. If not, user is idle and waits for the image/sound clip pair to change after the timer runs out. If either user stops the timer or timer runs out, application waits for pre-selected value of inter-image time period and goes to next image/sound value.

I have the following structure:

I call

while(true)
{
SwingUtilities.invokeAndWait(displayTimer);
}

in my run() method.

My Runnable is

private final Runnable displayTimer= new Runnable()
{
public void run()
{
 displayElapsed(System.currentTimeMillis() - startTime);
}

};

with startTime initialized later on and being starting reference point for beginning of task.

My displayElapsed()method is messy, checking whether the timer either stopped through user input or inactivity. If not, then it updates the jLabel responsible for the timer. If it did, it calls a startInteraction() method.

startInteraction() prepares new image and sound, displays and plays each respectively, makes a new thread updater and starts it.

I also have a mouseListener that listens for user input. It calls updater.interrupt() on user click.

Now, the question. I know that swing is thread-unsafe. There are definitely hiccups in the behavior, as sometimes it doesn't answer to user mouseclicks right away and sometimes goes through two image/sound pairs without proper waiting amount. Labels also do not get updated immediately.

In general, structure looks like a mess that I can't really explain logically.

All I know is I start a new thread for every displayElapsed I do and I interrupt it every time there is user or idle stop. So technically each thread should be in sequence.

There has to be a much better way to do this, and I wanted to see what would be a good start in rewriting this one.

1

There are 1 best solutions below

0
On

Have a look at this article about SwingWorker. The problems your program is running into is that the event dispatch thread (which is the one and only thread used to render the user interface) is being blocked by your infinite loop because the runnable is executing synchronously in the EDT.

What you want is to run your timer code in a different thread, and in this thread, post periodic tasks to update the label in the EDT. The SwingWorker class will help you accomplish this. To do this, you

  1. subclass (or create anonymous) SwingWorker
  2. implement doInBackground to have your timing loop
  3. within the timing loop, call publish to pass a timestamp (or whatever your want to put in the label)
  4. implement process to update the label
  5. instantiate the worker and call run.