I am having a hard time to use the Swing worker to work with my project. It has two programs, one is the logic (full program) and the other is GUI. I am calling the logic program from the GUI. And because of its unresponsiveness, I tried using Swing worker. But even if I use Swing worker, its still unresponsive. If I run the program, it displays the GUI, but if I click on start, the another program starts and it becomes unresponsive.
This the snippet of GUI program (full program):
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
state.setText("Listening");
System.out.println("Started Listening");
state.setBackground(new Color(51, 204, 0));
doRun(args);
}
});
public void doRun(String[] args) {
SwingWorker<Void, String> worker = new SwingWorker<Void, String>(){
#Override
protected Void doInBackground() throws Exception {
// Object to use from another program
HelloWorld obj = new HelloWorld();
obj.main(args);
return null;
}};
worker.execute();
}
Because it requires interaction, it may be inconvenient to run HelloWorld#main() in the background. As suggested here, instantiate a LiveSpeechRecognizer directly in your SwingWorker and publish() interim results for display in the GUI. You can specify Configuration information in the SwingWorker constructor or pass it as a parameter. In outline based on examples here and here,
private class BackgroundTask extends SwingWorker<Void, String> {
LiveSpeechRecognizer recognizer;
public BackgroundTask() {
statusLabel.setText((this.getState()).toString());
Configuration configuration = new Configuration();
configuration.setAcousticModelPath("resource:/edu/cmu/sphinx/models/en-us/en-us");
configuration.setDictionaryPath("resource:/edu/cmu/sphinx/models/en-us/cmudict-en-us.dict");
configuration.setLanguageModelPath("resource:/edu/cmu/sphinx/models/en-us/en-us.lm.dmp");
recognizer = new LiveSpeechRecognizer(configuration);
recognizer.startRecognition(true);
}
#Override
protected Integer doInBackground() {
while (!isCancelled()) {
SpeechResult result = recognizer.getResult();
List<WordResult> list = result. getWords();
for (WordResult w : list) {
// get information to publish, e.g. getPronunciation()
// publish(getSpelling());
}
}
}
#Override
protected void process(java.util.List<String> messages) {
statusLabel.setText((this.getState()).toString());
for (String message : messages) {
textArea.append(message + "\n");
}
}
#Override
protected void done() {
recognizer.stopRecognition();
statusLabel.setText((this.getState()).toString() + " " + status);
stopButton.setEnabled(false);
startButton.setEnabled(true);
bar.setIndeterminate(false);
}
}
Related
I have to perform two tasks. I like two threads perform each task simultaneously. The tasks don't share data.
Before the tasks start, is shown a dialog with a info "Wait, processing...".
Here the codes:
final JDialog dialog = new JDialog(this, true);
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
#Override
protected void done() {
// Must close dialog? The other finished?
}
};
SwingWorker<Void, Void> worker2 = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
#Override
protected void done() {
// Must close dialog? The other finished?
}
};
worker.execute();
worker2.execute();
dialog.setVisible(true);
// Must close dialog?
I would like to close the dialog only when the two threads ended. How to know when they ended? Who and when should close the dialog?
Update: the threads must run simultaneously, not in sequential mode.
Create a CountDownLatch, set to 2
Create your two SwingWorkers, passing each a reference to the CountDownLatch. In there done methods, call countDown on the latch. Do this in the done method, as it will be called regardless of how the doInBackground method exited (ie in case it throws an Exception)
Create a third SwingWorker, passing it a reference to the CountDownLatch, in this worker wait for the latch in the doInBackground method. Once this SwingWorker's done method is called, you should now be able to dispose of the dialog safely
You should call get() on both workers
For now I have made a sample code which will help you to understand the logic behind this.
import java.awt.BorderLayout;
import javax.swing.*;
public class DemoTest {
JFrame frame = new JFrame();
JLabel lbl1 = new JLabel();
JLabel lbl2 = new JLabel();
SwingWorker<Void,Void> worker1 = new SwingWorker<Void,Void>()
{
#Override
protected Void doInBackground() throws Exception {
for(int i = 0;i<=100;i++)
{
lbl1.setText("Counter1 Value:"+Integer.toString(i));
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}
return null;
}
#Override
protected void done()
{
lbl1.setText("Thread 1 completed its job");
worker2.execute();
}
};
SwingWorker<Void,Void> worker2 = new SwingWorker<Void,Void>()
{
#Override
protected Void doInBackground() throws Exception {
for(int i = 0;i<=100;i++)
{
lbl2.setText("Counter1 Value:"+Integer.toString(i));
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}
return null;
}
#Override
protected void done()
{
lbl2.setText("Thread 2 completed its job");
}
};
public DemoTest()
{
frame.setSize(400,400);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(lbl1,BorderLayout.NORTH);
frame.add(lbl2,BorderLayout.SOUTH);
frame.setVisible(true);
try
{
worker1.execute();
}
catch(Exception e)
{
e.printStackTrace();
}
//close dialog box
}
public static void main(String []args)
{
DemoTest d = new DemoTest();
}
}
I would use something like a counting lock for this. It is definitely using the least possible resources. The class below is a counting lock. Basically you initialise it with the constructor and specify the number of threads you need to wait for.
In the main thread (or UI thread) you call "waitForAll()" once you are done with setup. You can see that waitForAll is basically waiting for a notify from any other thread. If a notify is received it checks whether or not the number of active workers has reached zero. If the number of active workers is still greater 0 it waits again.
The workers however call unlock() on the lock. Notify decreases the counter by one and calls notify() which makes the main thread wake up and perform the above mentioned procedure.
public class CountingLock {
private int counter;
/**
* Number of workers
*
* #param n
*/
public CountingLock(int n) {
this.counter = n;
}
/**
* Wait until counter == 0
* #throws InterruptedException
*/
public synchronized void waitForAll() throws InterruptedException {
while(counter > 0) {
this.wait();
}
}
/**
* Deduce counter and notify
*/
public synchronized void unlock() {
this.counter--;
this.notify();
}
}
In the dialog prior launching the threads do the following:
CountingLock lock = new CountingLock(2);
/** put your thread setup code from your example here */
lock.waitForAll();
dialog.setVisible(false);
Make sure to pass a reference of lock to your threads and at the end of each thread call the following:
lock.unlock();
As per the comment to this answer, Java as of Java 1.5 (verified) provides a class java.concurrent.CountDownLatch with the exactly same behaviour. The use is well documented in the API.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html
example with CoundDownLatch
CountDownLatch lock = new CountDownLatch(2);
/** put your thread setup code from your example here */
lock.await();
dialog.setVisible(false);
In the threads do the following:
lock.countDown();
full example
final CountingLock lock = new CountingLock(2);
final JDialog dialog = new JDialog(this, true);
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
#Override
protected void done() {
// Must close dialog? The other finished?
lock.unlock();
}
};
SwingWorker<Void, Void> worker2 = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
#Override
protected void done() {
// Must close dialog? The other finished?
lock.unlock();
}
};
worker.execute();
worker2.execute();
dialog.setVisible(true);
lock.waitForAll();
dialog.setVisible(false);
Actually you should also consider to move the waitForAll or await call and setting dialog.setVisible(false) in another background thread since you most likely will not want the UI to stall.
I am doing a project that need to get page content from web page in Java, and sometimes, I need to execute some javascript on the web page and them get the modified content. So I choose to use SWT tool. Here is part of the code:
public void run(){
Display.getDefault().asyncExec(new Runnable(){
public void run(){
display = Display.getDefault();
shell = new Shell(display,SWT.CLOSE | SWT.MIN |SWT.TITLE);
shell.setText("Web Page");
shell.setSize(1024,768);
browser = new Browser(shell, SWT.NONE);
browser.setBounds(0, 0, 1010,700);
browser.addProgressListener(new ProgressListener() {
#Override
public void completed(ProgressEvent event) {
boolean success = browser.execute(script);
if(success || script.length()==0){
model.setHtml(browser.getText());
}
shell.dispose();
}
#Override
public void changed(ProgressEvent event) {
}
});
browser.setUrl(url);
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
});
}
And I am calling the the run() function within a class worker which extends from SwingWorker. The worker class is defined like this:
public class worker extends SwingWorker<Object,Integer>{
private ScrapingModel model;
private ScrapingView view;
private int[] indices;
public worker(ScrapingView v, ScrapingModel m, int[] ins){
model = m;
view = v;
indices = ins;
}
#Override
protected Object doInBackground() throws Exception {
int length = indices.length;
for(int i=0;i<indices.length;i++){
int index = indices[i];
//here call the run() function, sorry I skipped some code
publish((i+1)*100/length);
}
return null;
}
#Override
protected void process(List<Integer> chunks) {
for (Integer chunk : chunks) {
view.progressBar.setValue(chunk);
}
}
}
Here is the problem: the code wthin Display.getDefault().asyncExec never executes when I call the run() function in worker class. However, if I tried to call run() outside worker class, it could be executed. Any ideas?
Instead of wrapping the Runnable in an asyncExec
Display.getDefault().asyncExec(new Runnable(){
// swt code to open shell
});
Create a new Thread
Runnable r = new Runnable(){
// swt code to open shell
}
Thread t = new Thread(r);
th.start();
I use Swing Application Framework in my program. And I have some long-time work. I use org.jdesktop.application.Task for it. Another programmer wrote two Tasks before I took this project (I can not ask him about the programm). When Tasks are executing user sees progress bar without showing percent complete, but what shows "Wait" message and user can not click to a main window while Task does not ended. It is fine! But I could not find place where ProgressBars was created. May be it is described in some xml-file or property-file?
Also I wrote another Tasks and when they run, progress bar which I created is not displayed or displayed incorrectly. I read about ProgressBar and ProgressMonitor, but it does not help me.
Programm continue to run after someTask.execute(), but I want to it displays ProgressBar, ProgressMonitor or something else and user can not click the main window and window will display correctly. Now window has black "blocks" when user change it.
May be I need use org.jdesktop.application.TaskMonitor. I try to use it as here https://kenai.com/projects/bsaf/sources/main/content/other/bsaf_nb/src/examples/StatusBar.java?rev=235 , but my main window is displayed incorrectly and my ProgressBar is not displayed.
I need to when Task is running program waits it, but user can see ProgressBar, can cancel the operation and can not click to the main window. How can I do it?
Here my code:
public class A{
#Action(name = "ActionName", block = Task.BlockingScope.APPLICATION)
public RequestInfoTask requestInfo() {
RequestInfoTask task = new RequestInfoTask(Application.getInstance());
isSuccessedGetInfo=false;
task.addTaskListener(new TaskListener.Adapter<List<InfoDTO>, Void>() {
#Override
public void succeeded(TaskEvent<List<InfoDTO>> listTaskEvent) {
isSuccessedGetResources=true;
}
});
//Here I want to the program shows ProgressMonitor and user can not click to the main window.
//But small window with message "Progress..." is displayed for several seconds and disappear.
ProgressMonitor monitor = new ProgressMonitor(getMainView(), "Wait! Wait!", "I am working!", 0, 100);
int progress = 0;
monitor.setProgress(progress);
while(!task.isDone()){
monitor.setProgress(progress+=5);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
monitor.setProgress(100);
//This code must run after "task" finishes.
if(isSuccessedGetInfo){
MyTask2 task2 = new MyTask2(Application.getInstance());
isSuccessedTask2=false;
task2.addTaskListener(new TaskListener.Adapter<Map<?,?>, Void>(){
#Override
public void succeeded(TaskEvent<Map<String, ICredential>> arg0) {
isSuccessedTask2=true;
}
});
//Do something with results of task2.
}
return task;
}
}
public class RequestInfoTask extends Task<List<InfoDTO>, Void> {
public RequestInfoTask(Application application) {
super(application);
}
#Override
protected List<InfoDTO> doInBackground() throws Exception {
List<InfoDTO> result = someLongerLastingMethod();
return result;
}
}
Part of your problem sounds like it comes from not using the EDT correctly. Any long running task needs to be started in it's own thread to keep the GUI responsive and repainting.
Ideally you'd be following a MVC pattern. In that case you place your Progress Bar in the view, your flag (that indicates whether the task should be running still) in the control, and your long running task in in the Model.
From that point, if your model checks periodically if it should stop (Probably at good stopping points), you can reset everything.
Here's an example with MVC:
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
public class ProgressBarDemo{
public static class View extends JPanel{
Controller control;
public JProgressBar progressBar = new JProgressBar(0, 100);
JButton button = new JButton("Start Long Running Task");
public View(Controller controlIn){
super();
this.control = controlIn;
setLayout(new BorderLayout());
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
//Toggle between running or not
if(control.isRunning){
control.isRunning = false;
button.setText("Canceling...");
button.setEnabled(false);
} else{
control.isRunning = true;
button.setText("Cancel Long Running Task");
control.startTask();
}
}});
progressBar.setStringPainted(true);
add(progressBar);
add(button, BorderLayout.SOUTH);
}
}
//Communications gateway
public static class Controller{
View view = new View(this);
boolean isRunning = false;
public void updateProgress(final int progress){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
view.progressBar.setValue(progress);
}});
}
public void reset(){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
isRunning = false;
view.button.setText("Start Long Running Task");
view.progressBar.setValue(0);
view.button.setEnabled(true);
}});
}
public void startTask(){
LongRunningClass task = new LongRunningClass(this);
new Thread(task).start();
}
}
public static class LongRunningClass implements Runnable{
Controller control;
public LongRunningClass(Controller reference){
this.control = reference;
}
#Override
public void run() {
try {
for(int i = 0; i < 11; i++){
//Monitor the is running flag to see if it should still run
if(control.isRunning == false){
control.reset();
break;
}
control.updateProgress(i * 10);
Thread.sleep(3000);
}
control.reset();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
// Create and set up the window.
JFrame frame = new JFrame("LabelDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Add content to the window.
frame.add(new Controller().view);
// Display the window.
frame.pack();
frame.setVisible(true);
}
}
I am writing a piece of code using Java Swing. Basically what it does is that it processes some lengthy task. While the task is running, I want to have a waiting pop-up window with a GIF image in it.
My question is that
final InfoDialog infoDialog = new InfoDialog("Parsing file: " + fileToBeUploaded.getName());
final File finalFileToBeUploaded = fileToBeUploaded;
class FileParsingWorker extends SwingWorker<Void, String> {
#Override
protected Void doInBackground() throws Exception {
String text = fileParsers.parseFile(finalFileToBeUploaded);
publish(text);
return null;
}
#Override
protected void process(List<String> chunks) {
infoDialog.setVisible(false);
}
}
infoDialog.setVisible(true);
FileParsingWorker fileParsingWorker = new FileParsingWorker();
fileParsingWorker.execute();
The InfoDialog is the small UI pop-up window with a GIF animation in it. Basically, I put the lengthy task in the worker but the UI's setVisibles in two places. I am thinking if there is any ways I can run the InfoDialog UI in a thread so that I can reuse that bit of code?
The problem I have is that I want to try to run the InfoDialog indefinitely until I deliberately stop it. If I put setVisible(true) in a thread, that thread immediately terminates and my UI won't be updated.
Can someone show me how to do this?
Please have a read on Concurrency in Swing specifically The Event Dispatch Thread. This is the thread on which all Swing components should be created and manipulated. i.e:
SwingUtilities.invokeLater(new Runnable () {
#Override
public void run() {
final InfoDialog infoDialog = new InfoDialog("Parsing file: " + fileToBeUploaded.getName());
final File finalFileToBeUploaded = fileToBeUploaded;
...
infoDialog.setVisible(true);
FileParsingWorker fileParsingWorker = new FileParsingWorker();
fileParsingWorker.execute();
}
});
Also I think another problem is you set the dialog back to invisible in overriden process(List<String> chunks) of the Swing worker, thus as the first chunk is read the dialog will be closed. I think Swing Workers done() method might be more what you want, and its executed on EDT:
class FileParsingWorker extends SwingWorker<Void, String> {
#Override
protected Void doInBackground() throws Exception {
String text = fileParsers.parseFile(finalFileToBeUploaded);
publish(text);
return null;
}
#Override
protected void process(List<String> chunks) {
//each chunk will get processed here
}
#Override
protected void done() {//when Swing worker is finished this method is called
infoDialog.setVisible(false);
}
}
I know the subject has already been seen on many Questions and has been answered, but still, I can't get trough it.
I just want to update a progressBar while extracting some stuff of a large xml file.
I thought it was enough to have the time-consuming loop in a different thread but ?..
All I managed to get is the progressBar either not showed at all, or updated at the end, just before it's closed.
Instanced somewhere near the launch of the application, I have:
public class SomeClass {
private SomeClass () {
myXMLParser reader = new myXMLParser();
CoolStuff fromXml = reader.readTheXml();
}
}
while showing and updating a JDialog with a JProgressBar:
public class LoadingDialog extends JDialog {
private JProgressBar progressBar;
/* ... */
public void progress() {
progressBar.setValue(progressBar.getValue() + 1);
}
}
So I have this myXMLParser:
public class myXMLParser {
private LoadingDialog loadingDialog = new LoadingDialog();
public CoolStuff readTheXml() {
CoolStuff fromXml = new CoolStuff();
while(manyIterations) {
loadingDialog.progress();
fromXml.add(some() + xml() + reading());
}
return fromXml;
}
}
I have seen many things with SwingWorker and using PropertyChange events update the progressBar, but examples are always given all-in-one, with the processing and the progressbar within the same class, and with classes within classes, and since I begin in Java, I wasn't able to translate that to my situation.
Any help ?.. Any (not too obvious) advices ?
Edit: So thanks to btantlinger it worked like that:
public class SomeClass {
private SomeClass () {
myXMLParser reader = new myXMLParser();
new Thread(new Runnable() {
#Override
public void run() {
CoolStuff fromXml = reader.readTheXml();
}
}).start();
}
}
public class LoadingDialog extends JDialog {
private JProgressBar progressBar;
/* ... */
public void progress() {
progressBar.setValue(progressBar.getValue() + 1);
}
}
public class myXMLParser {
private LoadingDialog loadingDialog = new LoadingDialog();
public CoolStuff readTheXml() {
CoolStuff fromXml = new CoolStuff();
while(manyIterations) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
loadingDialog.progress();
}
});
fromXml.add(some() + xml() + reading());
}
return fromXml;
}
}
You MUST update the JProgress bar on the Swing Event Dispatch Thread. You cannot modify Swing components on any other thread.
Your only other alternative would be to set the JProgress bar "indeterminate" before you start your thread where the progress bar will just go back and forth.
E.g
progBar.setIndeterminate(true);
See the SwingWorker javadoc:
http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
If you don't want to use the SwingWorker, another option is the SwingUtilities.invokeLater method
//inside your long running thread when you want to update a Swing component
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//This will be called on the EDT
progressBar.setValue(progressBar.getValue() + 1);
}
});
In addition to the code provided by #btantlinger, I found after testing that it required an additional line of code in order to update the progress bar on the UI thread while processing. See below.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressBar.setValue((int)percentage);
//below code to update progress bar while running on thread
progressBar.update(progressBar.getGraphics());
}
});