This week's giveaway is in the Android forum.
We're giving away four copies of Android Security Essentials Live Lessons and have Godfrey Nolan on-line!
See this thread for details.
The moose likes Swing / AWT / SWT and the fly likes Adding a progress bar to an otherwise non-gui app Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Java » Swing / AWT / SWT
Bookmark "Adding a progress bar to an otherwise non-gui app" Watch "Adding a progress bar to an otherwise non-gui app" New topic
Author

Adding a progress bar to an otherwise non-gui app

Joe Areeda
Ranch Hand

Joined: Apr 15, 2011
Posts: 307
    
    2

I think I'm being bitten by the lack of a thread safe event loop but I have no clue how to fix it.

The program is a Java Class with a main function. It can be called from the command line or embedded in another program or called from Matlab.

What it does is use a proprietary network protocol to transfer a boat load of data and generates a single image summarizing all that data. It can take a while.

So I created a jFrame with JLables telling what it's doing, and estimating how time left and a progress bar to keep people entertained while I max out their network.

Everything works fine except for occasional exception being printed in the console complaining about null pointers in the Event Loop thread:



As far I can tell everything works and there's no problems from this but a program that throws exceptions is not trust-worthy.

I've done most of my Swing programming with SAF but now that that is deprecated, I'm trying program Swing directly and obviously missing something.

My program basically creates a new object from my class derived from JFrame does a setVisible(true). Then calls methods of that class to call setText on a bunch of JLabels and setValue on a JProgressBar. Then calls dispose() when finished.

I suspect I somehow need to get those JFrame update methods inside the event loop but I'm not sure how to do it.

Can somebody point me to something to read?

Writing this post helped me express the problem much more clearly than could before, so now I have a few terms to Google, but I'd still appreciate any advice and criticism on the whole thing.

Joe


It's not what your program can do, it's what your users do with the program.
Darryl Burke
Bartender

Joined: May 03, 2008
Posts: 4523
    
    5

Joe Areeda wrote:Can somebody point me to something to read?

Concurrency in Swing


luck, db
There are no new questions, but there may be new answers.
Joe Areeda
Ranch Hand

Joined: Apr 15, 2011
Posts: 307
    
    2

Thanks Darryl,

I've been reading this and I seem to need to do things backwards. Not that that is a rare situation for me to be in. I get a lot out of trying to explain my problems so let's see.

In a normal GUI application as described in your link, an initial thread launches the event dispatch thread which may then launch a worker thread to do the processing.

In this case the complication is I would not only like to use the JFrame as an add on to command line programs which normally run in the background but also add it to long running Matlab processes. I could probably implement the Java programs as worker threads but that's not an option with Matlab.

So it seems my only option is to get the initial thread to synchronize with the ProgressBar object to set fields and then have something in the event loop like a timer event actually update the widgets.

I'd appreciate any comments and suggestions.

Joe
Darryl Burke
Bartender

Joined: May 03, 2008
Posts: 4523
    
    5

When you need to invoke Swing methods and constructors from a Thread other than the EDT, you need to wrap the code in a Runnable queued via SwingUtilities#invokeLater(...) or, rarely, invokeAndWait(...).
Joe Areeda
Ranch Hand

Joined: Apr 15, 2011
Posts: 307
    
    2

Darryl Burke wrote:When you need to invoke Swing methods and constructors from a Thread other than the EDT, you need to wrap the code in a Runnable queued via SwingUtilities#invokeLater(...) or, rarely, invokeAndWait(...).

Everything I've read agrees with you.

The trick, I think, is that the only routines that actually call the Swing methods have to be in that thread. So my current and half-baked plan is have thread safe ways to pass data between the worker and EDT and then do the actual update on a timer event, or possibly there is another way to generate an event. For this project a once a second update is fine.

When I get it to work, I'll post some details.

Thanks for your help Darryl!

Joe
Tony Docherty
Bartender

Joined: Aug 07, 2007
Posts: 2173
    
  47
For passing data between a worker thread and the EDT look at javax.swing.SwingWorker.
For a timer, if it needs to interact with the GUI look at using javax.swing.Timer else use java.util.Timer
Joe Areeda
Ranch Hand

Joined: Apr 15, 2011
Posts: 307
    
    2

Tony Docherty wrote:For passing data between a worker thread and the EDT look at javax.swing.SwingWorker.
For a timer, if it needs to interact with the GUI look at using javax.swing.Timer else use java.util.Timer


Thanks Tony.

I'm struggling with the SwingWorker concept. I tried to explain my confusion above but it's hard to describe what I don't understand.

Matlab use is the one I have no clue how to implement a SwingWorker thread. I have used SwingWorkers before and they are pretty straight forward, at least as far as multi-threading tasks go. But the problem is that they are spawned in the event loop as the result of some action by the user (or at start).

In my case I already have the Matlab event loop running the processing task that I want to spawn the EDT loop to only handle a Progress Dialog. For those of us not familiar with Matlab it uses Swing objects to implement application level GUI but it doesn't give us access to all of the Swing capabilities. In this case it's the progress bar widget and I think they have good reason for that.

I have a plan, no idea if it will work yet. At the very least I should be able to ask semi-intelligent questions when I run into trouble.

Joe
Tony Docherty
Bartender

Joined: Aug 07, 2007
Posts: 2173
    
  47
I have used SwingWorkers before and they are pretty straight forward, at least as far as multi-threading tasks go. But the problem is that they are spawned in the event loop as the result of some action by the user (or at start).

Any thread can start a SwingWorker, admittedly they are generally used as you describe but they are not restricted to that scenario.

I'm not clear as to how or what data is being passed from MatLab. If you are pulling it then the SwingWorker background thread can do that, if MatLab is pushing it you could use a producer-consumer design pattern to get the data to the SwingWorkers background thread.
Joe Areeda
Ranch Hand

Joined: Apr 15, 2011
Posts: 307
    
    2

Tony Docherty wrote:
I have used SwingWorkers before and they are pretty straight forward, at least as far as multi-threading tasks go. But the problem is that they are spawned in the event loop as the result of some action by the user (or at start).

Any thread can start a SwingWorker, admittedly they are generally used as you describe but they are not restricted to that scenario.

I understand. I'm trying to work through my confusion.

I think my issue here is I don't see anything special about the SwingWorker vs another Thread class. Since I already have the worker/processing thread working and validated I'm reluctant to change it in the java code example, and I'm not sure it's possible in the Matlab case.

I'm not clear as to how or what data is being passed from MatLab. If you are pulling it then the SwingWorker background thread can do that, if MatLab is pushing it you could use a producer-consumer design pattern to get the data to the SwingWorkers background thread.

Thanks, I go reread the producer/consumer pattern. That is essentially my plan.

The data in the current implementation is being pushed from Matlab to Java and I believe it has to be done that way. It's straight forward to call Java from Matlab and as far as I can tell impossible to call Matlab from Java without setting up some sort of socket listener.

I haven't found any multi-threading in user level Matlab code outside the Parallel Toolbox which cannot be required for this project.

The current implementation has Matlab GUI sets up a bunch of parameters, then on a button push the transfer or crunch function is called which then pushes regular status updates to the Progress Dialog. I'm thinking that's a fairly general pattern and if I can encapsulate all this synchronization into the Progress Dialog class that it will be easiest to reuse.

Joe
Tony Docherty
Bartender

Joined: Aug 07, 2007
Posts: 2173
    
  47
I think my issue here is I don't see anything special about the SwingWorker vs another Thread class.

SwingWorker is essentially an implementation of a producer-consumer design pattern where the producer is the worker thread and the consumer is the EDT. You do your work on the worker thread and then call publish() to pass some data to the EDT. The EDT runs the process() method to get the published data and update the GUI.

The data in the current implementation is being pushed from Matlab to Java and I believe it has to be done that way.

Ok, so essentially you need to take the data passed to Java by MatLab and pass it to the EDT to update the GUI.
There are a couple of ways I can think of for doing this:
1. For each piece of data you receive from MatLab you can process it and then create a Runnable with the data for the GUI. You pass this Runnable to EventQueue.invokeLater(). The runnable will be executed on the EDT and so can update the GUI.
2. You pass the data directly to your sub-class of SwingWorker. I'm not sure if any thread can call the SwingWorker's publish method or whether is has to be the worker thread but if any thread can then you process the data and pass the GUI data to the publish method(). If you can't use any thread then you can push the data to something like a java.util.concurrent.ConcurrentLinkedQueue and pop it from the queue using the worker thread and then call the publish() method.

Joe Areeda
Ranch Hand

Joined: Apr 15, 2011
Posts: 307
    
    2

Thanks Tony and Darryl, I really appreciate the discussion. I think I have the problem solved so I'll described what I did for review and so other might be able to find a solution if they have the same problem.

I am certainly not making any claims that is the best way or the only way to do this. In fact it's only positive is that it is the first way I've found that works.

My issues are a bit different from the general case but not much.

I have a degenerate case of the producer-consumer pattern in that I don't need a queue. If the worker (producer) sets progress to 10% and then sets it again to 20% before the progress dialog (consumer) deals with the first one, it only has to display the last value. We don't care about the missed ones. So I implement it with a value & boolean. I may change it to keep the last value and check if it's changed but I think it's more efficient if less elegant to check a boolean instead of compare strings.

So I have worker thread that already exists when we create the Event Dispatcher Thread (EDT). I have a Progress Bar class that is derived from JFrame that was created in the NetBeans GUI builder.

It's still not clear to me whether I need to implement the Runable interface and use SwingUtilities.invokeLater. Everything seems to work and even does what I expect if I just use new to create the object. I realize it is creating it's own EDT but that's actually what I want. Matlab's EDT is blocked by the processing program.

Now the issue is to only call any Swing methods from inside the EDT not the worker. So the way I implemented this is:

Class implements the ActionListener interface.
Constructor starts a Timer and the ActionPerformed method is the only place that updates any Swing component. It is a series of if statements like:

For each component there is a corresponding access function that looks like:


Then when all the processing is over we have to kill the time and close the window to stop the EDT.



It just ran a twenty minute process that didn't produce any errors and had a very responsive ProgressBar with the timer set at 250ms. No exceptions in the terminal window.

Please poke holes in my implementation, that's the main reason I posted it.

Joe
Tony Docherty
Bartender

Joined: Aug 07, 2007
Posts: 2173
    
  47
I have a degenerate case of the producer-consumer pattern in that I don't need a queue. If the worker (producer) sets progress to 10% and then sets it again to 20% before the progress dialog (consumer) deals with the first one, it only has to display the last value. We don't care about the missed ones.

Yes, that's is perfectly ok if you are only interested in the current value such as when updating a progress bar.

So I implement it with a value & boolean.

Not sure about the need for a boolean without seeing the whole code.
Do make sure you make proper use of synchronized code blocks if you are accessing variables from different threads. You'll possibly want to declare such variable as volatile as well.

It's still not clear to me whether I need to implement the Runable interface and use SwingUtilities.invokeLater

If your Timer is a javax.swing.Timer then this runs the action listeners on the EDT so as long as all your GUI updates are done by the Timer's action listeners this should work as is.

It just ran a twenty minute process that didn't produce any errors

If only I had a Pound for every time I'd heard someone say that only to have a bug reported as soon as the app goes live.
Joe Areeda
Ranch Hand

Joined: Apr 15, 2011
Posts: 307
    
    2

Not sure about the need for a boolean without seeing the whole code.
Do make sure you make proper use of synchronized code blocks if you are accessing variables from different threads. You'll possibly want to declare such variable as volatile as well.

Ah volatile, I've been bitten by forgetting to use that before. Thank you. Is the boolean necessary? Well it could just update everything on every timer tick, there's not much but this way I save a couple of nanoseconds every once in a while.
It's still not clear to me whether I need to implement the Runable interface and use SwingUtilities.invokeLater

If your Timer is a javax.swing.Timer then this runs the action listeners on the EDT so as long as all your GUI updates are done by the Timer's action listeners this should work as is.


If only I had a Pound for every time I'd heard someone say that only to have a bug reported as soon as the app goes live.

I'd settle for a dollar every time I said it and had it fail the next time I ran it. Agreed! There's a lot more testing to do.
 
It is sorta covered in the JavaRanch Style Guide.
 
subject: Adding a progress bar to an otherwise non-gui app
 
Similar Threads
Progress bar in jsp
Gui and Thread
SwingWorker and Communications with GUI
Main thread is hanging while 2 child threads running??
Threads... changing while loop....