Reputation: 23
I'm building a Swing application and one part of the functionality should be to process and output some text visually and audibly (using Mary TTS). I need some advice on the best way for the GUI and text processing classes to communicate.
The GUI class is a subclass of JPanel. Within that I have a class implementing Runnable, called LineProcesser, which prepares the text to be dispatched to an audio player. I'm using a thread executor to keep this off the EDT (that may not be the best way but it seems to achieve the result I'm after).
My intention is for LineProcessor to run through all the text and update a JTextArea at the end of each line. Additionally it will need to halt and wait for user input at certain points. After the user input has been completed the GUI class should tell it to resume processing.
The following code illustrates what I currently have:
public class MyPanel extends JPanel {
ExecutorService lineExecutor = Executors.newSingleThreadExecutor();
Runnable lineProcessor = new LineProcessor();
public class LineProcessor implements Runnable {
private int currentLineNo = 0;
public LineProcessor() {
// ...
}
@Override
public void run() {
// call getText();
// call playAudio();
currentLineNo++;
}
}
}
private JButton statusLbl = new JLabel();
private JButton mainControlBtn = new JButton();
private void mainControlBtnActionPerformed(ActionEvent evt) {
if (mainControlBtn.getText().equals("Start")) {
lineExecutor.submit(lineProcessor);
mainControlBtn.setText("Running");
}
}
}
How can LineProcessor notify GUI components that they need to change and how can it be paused and restarted from within the GUI? I'm confused as to whether I need a Swing Worker, property/event listeners or something else? The examples I've read sort of make sense but I can't see how I can apply them to the code I have here.
Upvotes: 2
Views: 5150
Reputation: 36601
What you are looking for is a SwingWorker
. This class allows to perform the work on a worker thread, having periodical updates on the EDT, and in the end update the EDT as well.
Several examples are available on SO and in the Swing tutorials. Just a few links
SwingWorker
SwingWorker
javadocReporting progress can be done with the publish
method, these results will be passed to the process
method in which you can update the UI. At the end, the done
method is called allowing you to perform some final UI updates.
For the pause/restart functionality ... you can use an invokeAndWait
in the doInBackground
method with a blocking method call (for example showing a JOptionPane
asking for user input). But if you start using invokeAndWait
in the doInBackground
it might be overkill to use the SwingWorker
and you can simply opt for the approach @Hovercraft Full Of Eels suggested
Upvotes: 3
Reputation: 20323
You will have to use both SwingWorker and Event methodology.
Upvotes: 4
Reputation: 285403
All you need to do is wrap any Swing calls in a Runnable, and queue it on the EDT via SwingUtilities.invokeLater(myRunnable);
. That's it. No need for a SwingWorker.
e.g.,
public class LineProcessor implements Runnable {
private int currentLineNo = 0;
Runnable LineProcessor = new LineProcessor(); // won't this cause infinite recursion?
public LineProcessor() {
// ...
}
@Override
public void run() {
// call getText();
// call playAudio();
currentLineNo++;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// *** Swing code can go here ***
}
});
}
}
Upvotes: 6