views:

105

answers:

2

I have a question regarding SwingWorker and Java GUI's.

I have several classes which process information, we can call them Foo1, Foo2, and Foo3. This processing can take a very long time.

These are all subclasses of Foo, however Foo is not called directly itself (the Foo[x] classes use methods inherited from Foo. In order to keep the EDT free to paint a progress bar, what is the best way to use SwingWorker when keeping my object hierarchy? Is it possible to have wrapper classes such as Foo1Worker extends SwingWorker and have its doInBackground() call Foo1.myProcessMethod()? Even though Foo1 does not extend SwingWorker, will this still work as I expect it to?

edit: to clarify my question, how can I make Foo[x] SwingWorkers even though they are already subclasses?

A: 

You'd need a SwingWorker if you needed to update GUI elements, e.g. calling routines such as SetText(). I've never thought about using them for non-GUI update tasks; I've always sub-classed Thread or implemented Runnable. I recommend that you try this with your Foo classes and see if the problem takes care of itself.

Pete
A SwingWorker is a wrapper that allows you to do processing as well as run things on the EDT to ensure proper GUI updates, unless I am not understanding something. Look at the example here for the use of it while processing and updating the GUI. http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html
Ryan
Further comment: obviously, the result of the data processing routines (your Foo routines) will have to be displayed to the screen in some way, at some point. What I do is have them keep the data in one of the Concurrent data structures (usually a 'ConcurrentHashMap' or 'ArrayBlockingQueue'), and then make a textbook-style 'SwingWorker' who reads and displays the data.
Pete
@Ryan: my point is, I have found it much better to use SwingWorkers only for what you absolutely need them for, which is direct updates to the GUI using 'Publish()' and 'Process()'. I separate out the actual data processing and calculations into straight-up 'Threads' or 'Runnables'. This has the additional benefit of completely separating my meat-and-potatoes code from my screen update code.
Pete
Thank you for the tips Pete - as one last question:In the middle of these threads, how would I alert the EDT that there is a change to the GUI if my Foo class is now Foo1 extends Foo implements Runnable ?
Ryan
With this technique you don't actively notify the EDT. Rather your Runnable/Thread will update some thread-safe data structure (whatever is appropriate from java.util.concurrent). Your SwingWorkers simply look at this data and see if there's anything new to update on the screen. For instance, if you had a string to display, an ArrayBlockingQueue would be a good choice. Your SwingWorker use Take(), which would have it sit around until a message shows up in the array, and then Publish it. Since my SwingWorkers are so simple, I just nest them in the Application.
Pete
There might be a simpler solution, but my application is quite chaotic (it is a real-time stock trading robot). There's no telling when and how much data will arrive from the broker, and the app involves several threads (traders) which could be in any number of functional states. So my tasks really don't end. Plus there is no particular order or time-frame in which GUI updates might be needed.
Pete
+2  A: 

I think the answer hinges critically on the type of data managed by Foo subclasses. If the results are homogeneous, just extend SwingWorker and instantiate concrete subclasses accordingly:

class Whatever {}

abstract class AbstractFoo extends SwingWorker<List<Whatever>, Whatever> {}

class Foo1 extends AbstractFoo {

    @Override
    protected List<Whatever> doInBackground() throws Exception {
        ...
    }
}

If each manages a different type, make the parent generic and instantiate each concrete subclass with the required type:

class Whatever {}
class Whichever {}

abstract class GenericAbstractFoo<T, V> extends SwingWorker<T, V> {}

class Foo2 extends GenericAbstractFoo<List<Whatever>, Whatever> {

    @Override
    protected List<Whatever> doInBackground() throws Exception {
        ...
    }
}

class Foo3 extends GenericAbstractFoo<List<Whichever>, Whichever> {

    @Override
    protected List<Whichever> doInBackground() throws Exception {
        ...
    }
}
trashgod
In the first example, Abstract Foo, is that supposed to be my super class `Foo`?
Ryan
@Ryan: Yes. It's not required, but it offers some safety and convenience to others who might use your API. In particular, it precludes inadvertently instantiating the base class. http://java.sun.com/docs/books/tutorial/java/IandI/abstract.html
trashgod