SwingWorker
is a lot simpler to use them it might seem.
Basically, you need to make a few basic decisions about what you want to achieve.
- Do you want to return periodically updates while the process is running or
- Do you want to return a result of the process…or both?
- Do you want to provide progression updates?
Depending on what you want to do, will change the way you declare the SwingWorker.
For example…
public class HardWorker extends SwingWorker<ReturnValueType, PeriodicalType> {
Where ReturnValueType
is the final result that will be generated by the worker and PeriodicalType
is the type of object that could be sent back to the UI thread should you want to perform periodical updates (these are values you can specify yourself).
You can specify Void
or Object
for either of these values should you not care
When executed, the SwingWorker
will call doInBackground
, this method will be called within its own thread, allowing to perform your long running task outside of the Event Dispatching Thread.
If you want to send a value back to the UI before the doInBackground
method has finished, you can call publish(instanceOfPeriodicalType)
. The values passed to this method will, eventually, be passed to the process
method.
Because it’s possible for multiple items to sent to the publish
method, the process
method provides a List<PeriodicalType>
argument. When called, this method will be executed within the context of the EDT, allowing you to up date the UI.
Once doInBackground
completes, it will return
a return value of type ReturnValueType
(or null
if you don’t care).
If you’re interested in this result, you should use SwingWorker#get
, but you should beware that this method will block until doInBackground
returns, meaning you shouldn’t call this method within the EDT until you know the doInBackground
method has returned. You can check the state of worker using it’s isDone
or isCancelled
methods, or…
You could use a PropertyChangeListener
and monitor the state
property or override the done
method of the SwingWorker
.
If you want to provide progress updates, while in the doInBackground
method, you can call setProgress
to update the progress of the worker. This will trigger a PropertyChangeEvent
named progress
, which you can monitor through the use of a PropertyChangeListener
. Calls to this listener will be made within the context of the EDT.
Take a look at:
- SwingWorker
- Worker Threads and SwingWorker
For more details.
Generally, in order to use a SwingWorker
, what you want to do, is separate your design into two groups. Every thing that can be done in the background and everything that needs to be done within the EDT.
You can start building the basic concept of your worker.
Basic Example…
This assumes a lot. Basically, it assumes that UI is already setup and this would be used to pick out new results and pass them back to a specific series.
Basically, as required, the worker would be insansiated, and the series passed to it…
GraphWorker worker = new GraphWorker(series);
worker.execute();
The work would then execute the query and pass the results back to the process
method
public class GraphWorker extends SwingWorker<Void, String[]> {
private TimeSeries series;
private Second sec;
public GraphWorker(TimeSeries series) {
this.series = series;
sec = new Second();
}
@Override
protected Void doInBackground() throws Exception {
ResultSet rs;
Connection conn = null;
try {
conn = (Connection) getMySqlConnection();
Statement st = conn.createStatement();
rs = st.executeQuery("SHOW GLOBAL STATUS");
while (rs.next()) {
publish(new String[]{rs.getString(1), rs.getString(2)});
}
} finally {
conn.close();
}
return null;
}
@Override
protected void process(List<String[]> chunks) {
for (String[] value : chunks) {
try {
int iValue = Integer.parseInt(value[1]);
series.add(sec, Value);
} catch (NumberFormatException exp) {
exp.printStackTrace();
}
}
}
}