I have some long running tasks in my eclipse RCP (e4) application that I implemented using the Job API. The Job is started immediately (before GUI is shown).
private class MyJob extends Job {
#Override
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask("do some long stuff", 4);
doStep1();
monitor.worked(1);
doStep2();
monitor.worked(1);
doStep3();
monitor.done();
}
// methods for the steps follow here
}
Now I want to display a progress bar somewhere in my GUI to show if MyJob is still running.
I have tried this using the IJobManager:
public class MyStatusbar {
private ProgressBar progressBar;
#Inject
UISynchronize sync;
#PostConstruct
public void createControls(Composite parent) {
progressBar = new ProgressBar(parent, SWT.SMOOTH);
progressBar.setBounds(100, 10, 200, 20);
// Setting the progress monitor
IJobManager manager = Job.getJobManager();
final IProgressMonitor p = (IProgressMonitor) new IProgressMonitor() {
#Override
public void worked(final int work) {
sync.syncExec(new Runnable() {
#Override
public void run() {
System.out.println("Worked");
progressBar.setSelection(progressBar.getSelection()
+ work);
}
});
}
// [...]
};
ProgressProvider provider = new ProgressProvider() {
#Override
public IProgressMonitor createMonitor(Job job) {
return p;
}
};
manager.setProgressProvider(provider);
}
}
But my Job is not shown in the status bar. I suppose it has something to do with my starting the job before the GUI is there but I'm not sure.
So I have two questions:
What am I doing wrong?
Is my approach correct or are there better ways to do this?
You do need to create the progress monitor and call IJobManager.setProgressProvider before the Job starts (which is when ProgressProvider.createMonitor is called).
I set up my progress provider in the #PostContextCreate method of my LifeCycle class.
Related
I have a JProgressBar that I need to set a new minimum, maximum and progress value each time a task of a queue is done, using the code below:
this.progressBar.setMinimum(minimum);
this.progressBar.setMaximum(maximum);
this.progressBar.setValue(progress);
But, I noticed that sometimes, the setMaximum(int) method doesn't seems to work, because the progress bar still working with the old maximum value.
Then I wrote some test code and ran it:
progressBar.setMaximum(10);
System.out.println(progressBar.getMaximum());
Sometimes it prints 10 as expected, and sometimes prints the old value: anything different from 10.
I spent hours on Google and javadocs, tried to call revalidate() and repaint() on JProgressBar's parent, and nothing. I also tried to call Thread.sleep(10) to wait AWT threads to run another tasks and didn't work.
Any ideas?
EDIT: Provided some more code:
/* Applet that construct the view and init a Thread. */
public class FastApplet extends Applet {
private JProgressBar progressBar;
private JPanel panel;
private Runnable runnable;
#Override
public void init() {
try {
java.awt.EventQueue.invokeAndWait(new Runnable() {
#Override
public void run() {
createAndShowGUI();
initThreads();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void createAndShowGUI() {
panel = new JPanel();
progressBar = new JProgressBar();
progressBar.setStringPainted(true);
panel.add(progressBar);
}
private void initThreads() {
runnable = new MyRunnable(progressBar);
Thread thread = new Thread(runnable);
thread.start();
}
}
/* Runnable that update progress and call setMaximum(int) on JProgressBar */
public class MyRunnable {
private int progress;
private final JProgressBar progressBar;
MyRunnable(JProgressBar progressBar) {
this.progressBar = progressBar;
}
#Override
public void run() {
// do the tasks and update the progressBar using progressBar.setValue(progress)
// when done, reset the progress bar with the a new maximum:
defineNewProgressBar(0, 0, newMaximum);
}
public void defineNewProgressBar(int progress, int minimum, int maximum) {
this.progress = progress;
Component component = progressBar.getParent();
JPanel panel = (JPanel) component;
this.progressBar.setMinimum(minimum);
this.progressBar.setMaximum(maximum);
this.progressBar.setValue(progress);
panel.revalidate();
panel.repaint();
}
}
You wrote in your comments that you call setMaximum() not from the EDT. You should call it from the EDT like this:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
progressBar.setMaximum(10);
}
});
If you use Java8, you can do this with using a lambda expression:
SwingUtilities.invokeLater(()->progressBar.setMaximum(10));
You can use SafeProgressBarUpdaterThread :
progressBarUpdater = new SafeProgressBarUpdaterThread(progressBar);
//...
progressBarUpdater.setMaximum(maximum);
progressBarUpdater.setValue(value);
java.awt.EventQueue.invokeLater(progressBarUpdater);
I'm working on an Omaha online poker client written in javaFX+java.
I need to show an anchorPane containing 3 buttons after control.call() finishes executing. I know for a fact that control.call() finishes executing but for some reason task.setOnSucceeded(new EventHandler() {'s handle method does not update the User interface.
What am I doing wrong?
public void newRound() {
sog = StateOfGame.PREFLOP;
ControlGameOnNewThread control = new ControlGameOnNewThread();
Task task = new Task() {
#Override
protected Object call() throws Exception {
control.call();
return null;
}
};
task.setOnSucceeded(new EventHandler() {
#Override
public void handle(Event event) {
if (client.getAction() == FirstToAct.me) {
System.out.println("Task finsished");
showOptions(client.getToCall());
opponentBetField.setText(new Integer(opp.chipsInvested).toString());
myBetField.setText(new Integer(client.chipsInvested).toString());
System.out.println("Task finsished");
}
}
});
new Thread(task).start();
}
The problem is that you are updating the user interface in the other thread.. if you are in the other thread and you want to update the user interface
You need to call the
Platform.runLater(new Runnable() {
#Override public void run() {
//Update UI here
}
});
calling this will call the main thread and update all the necessary update to the user interface
EDIT
public void newRound() {
sog = StateOfGame.PREFLOP;
ControlGameOnNewThread control = new ControlGameOnNewThread();
Task task = new Task() {
#Override
protected Object call() throws Exception {
control.call();
return null;
}
};
task.setOnSucceeded(new EventHandler() {
#Override
public void handle(Event event) {
if (client.getAction() == FirstToAct.me) {
Platform.runLater(new Runnable() {
#Override public void run() {
System.out.println("Task finsished");
showOptions(client.getToCall());
opponentBetField.setText(new Integer(opp.chipsInvested).toString());
myBetField.setText(new Integer(client.chipsInvested).toString());
System.out.println("Task finsished");
}
});
}
}
});
new Thread(task).start();
}
As you override the call() method, you can override the succeeded() method: (See last example in the javadoc of Task.)
#Override protected void succeeded() {
super.succeeded();
updateMessage("Done!");
}
succeeded() is already called on the JavaFX Application Thread, so you do not need to do this for yourself.
Are you sure, that the code in your handle method isn't called? Maybe a NullPointerException is thrown, which you might not see? Is the comparison working as expected?
Try moving the code with if (client.getAction()... into the overridden succeeded() method and put a println before the if-statement in order to see whether it is called or not.
(EDIT: typos)
Your information has been helpful, but i think all methods suggested would have worked (including my initial one). The problem is that the task was never ended that's why the onTaskSucceded was never executed. In order to have the task exit after it has finished, i had to se the daemon to true:
Thread thread = new Thread(task);
thread.setDaemon(true);
thread.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 want to execude some code every second in android, but I'd like to do is in one thread (main thread). So far I have this:
locationTimer = new Timer("locationTimer", false);
locationTimer.schedule(new LocationCheckerTask(this), 0, 1000);
public class LocationCheckerTask extends TimerTask {
private GeoWatcher watcher;
public LocationCheckerTask(Context context) {
watcher = new GeoWatcher(context);
}
#Override
public void run() {
// funky stuff
}
}
Unfortunately, Timer class runs it's tasks on another thread.
Why I want to do this in a single thread?
Code in run() method will be executing really fast, so I figured I don't need another thread for it. What I want to do is to construct separate threads in run() method based on condition calculated every second. So instead of having child thread constructing another threads, I'd like to do this on the main one.
You can do this with Handler
public class Job implements Runnable{
private Handler handler;
public Job () {
handler = new Handler(Looper.getMainLooper());
loop();
}
#Override
public void run() {
// funky stuff
loop();
}
private void loop() {
handler.postDelayed(this, 1000);
}
}
use runOnUiThread(Runnable) method of Activity to run the task in UI Thread
public class LocationCheckerTask extends TimerTask {
private GeoWatcher watcher;
public LocationCheckerTask(Context context) {
watcher = new GeoWatcher(context);
}
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// funky stuff
}
});
}
}
the Handler is a perfect candidate for such tasks (dont try to combine TimerTask + runOnUiThread - it is useless as it uses a Handler under the hood)
private Runnable fiveSecondRunnable = new Runnable() {
#Override
public void run() {
if (count5 < 0) {
switchT030Sec();
} else {
tvSec5.setText(""+count5);
Log.v("5sec set", "yes");
count5--;
man.postDelayed(this, 1000);
}
}
};
and start it by calling
man.post(fiveSecondRunnable);
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());
}
});