Can't figure this one out. Using worker or invokeLater, the UI still freeze. After each file is downloaded, I want a JList to be updated. But the JList will only update after the tread returns.
Here is the code:
public class MyUi extends javax.swing.JFrame{
...
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt){
SwingUtilities.invokeLater(new Runnable() {
//To get out of the event tread
public void run() {
dl();
}
});
}
private void dl(){
...
//ini and run the download class
Download myDownload = new Download();
myDownload.doDownload(myDlList);
}
public void updateJlist(String myString){
myModel.addElement(myString);
jList1.repaint();
}
}
public class Download{
...
public void doDownload(String[] fileName){
for(int i=0; i<fileName.length; i++){
...//download action...
//for my jList1 to be updated after each file.
MyUi.updateJlist(fileName[i]);
}
}
}
Any example would help.
invokeLater does exactly the opposite of what you expect it to do - it runs operations on the EDT, which explains the behaviour.
Download the file on a background thread and wrap just updateJlist() in a Runnable.
SwingWorker would be more reliable.
Addendum: As #mre notes, SwingWorker also makes it easy to report interim results, as shown here.
I have create a WorkerThread class which take care of Threads and GUI current/main thread . i have put my GUI application in construct() method of WorkerThread when an event fire to start XXXServer then all threads are activate and GUI work smoothlly wihout freeze. have a look.
/** * Action Event * * #see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */
public void actionPerformed(ActionEvent ae) {
log.info("actionPerformed begin..." + ae.getActionCommand());
try {
if (ae.getActionCommand().equals(btnStart.getText())) {
final int portNumber = 9990;
try {
WorkerThread workerThread = new WorkerThread(){
public Object construct(){
log.info("Initializing the Server GUI...");
// initializing the Server
try {
xxxServer = new XXXServer(portNumber);
xxxServer.start();
btnStart.setEnabled(false);
} catch (IOException e) {
// TODO Auto-generated catch block
log.info("actionPerformed() Start button ERROR IOEXCEPTION..." + e.getMessage());
e.printStackTrace();
}
return null;
}
};workerThread.start();
} catch (Exception e) {
log.info("actionPerformed() Start button ERROR..." + e.getMessage());
e.printStackTrace();
}
} else if (ae.getActionCommand().equals(btnStop.getText())) {
log.info("Exit..." + btnStop.getText());
closeWindow();
}
} catch (Exception e) {
log
.info("Error in ServerGUI actionPerformed==="
+ e.getMessage());
}
}
Related
I have a Java swing UI where I need to disable a button on the UI if I could not detect an active internet connection.
The code function properly so far, but when I get disconnected from the internet, it does not retrigger the method to update the boolean flag.
How can I add an event on that flag to let my button consume it during the lifetime of the application?
public class Main {
private static JButton button;
private static boolean testButtonEnabled;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
/*
* function that returns true/false if connected to the internet
*/
if(Utils.isConnectedToInternet()) {
logger.debug("System is connected to the internet");
testButtonEnabled=true;
} else {
logger.debug("System is not connected to the internet");
testButtonEnabled=false;
}
Main window = new Main();
window.frame.setVisible(true);
button = new JButton("my button");
/*
* set the internet status
*/
button.setVisible(testButtonEnabled);
}
}
}
}
Again, this code:
SwingWorker<Void, String> worker = new SwingWorker<Void, String>()
{
public Void doInBackground()
{
while(true)
{
try {
isConnectedToInternet = Utils.isConnectedToInternet();
if (isConnectedToInternet) {
btn_online2.setEnabled(isConnectedToInternet);
} else {
btn_online2.setEnabled(isConnectedToInternet);
}
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
worker.execute();
is dangerous since it makes mutational changes to a Swing component from a background thread. While this code may work 95% of the time, it can fail in unpredicatable ways and at unpredicatable times. Better to only mutate Swing components on the event thread. For instance, even this would be better:
SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
#Override
public Void doInBackground() {
while(true) {
try {
isConnectedToInternet = Utils.isConnectedToInternet();
// note that there is no need for the if/else block
SwingUtilities.invokeLater(() -> {
btn_online2.setEnabled(isConnectedToInternet);
});
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
worker.execute();
or better still, using SwingWorker's publish/process:
SwingWorker<Void, Boolean> worker = new SwingWorker<Void, Boolean>() {
#Override
public Void doInBackground() {
while(true) {
try {
isConnectedToInternet = Utils.isConnectedToInternet();
// note that there is no need for the if/else block
publish(Utils.isConnectedToInternet());
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
protected void process(List<Boolean> chunks) {
for (Boolean chunk : chunks) {
btn_online2.setEnabled(chunk);
}
}
};
worker.execute();
I was able to resolve using the following method in the initialize() of the frame.
Adding that change part of the swingworker allowed the button to check the flag and assign it to itself whenever it changes.
Now whenever the internet is disconnected the button is disabled and whenever connected the button is enabled.
SwingWorker<Void, String> worker = new SwingWorker<Void, String>()
{
public Void doInBackground()
{
while(true)
{
try {
isConnectedToInternet = Utils.isConnectedToInternet();
if (isConnectedToInternet) {
btn_online2.setEnabled(isConnectedToInternet);
} else {
btn_online2.setEnabled(isConnectedToInternet);
}
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
worker.execute();
Background:
A well-known Swing best-practice requirement is that code that
interacts with the Swing framework must also execute in EDT (Event
Dispatch Thread).
I thus changed my code to have my JFreeChart-based updates to run in EDT.
However, a complete chart display task that usually took about 7 minutes to finish on a “normal” thread, become a several hours task when running in EDT!
What am I doing wrong? Did I misunderstood the Swing Concurrency lesson? Do I really have to run org.jfree.data.time.TimeSeries.addOrUpdate(date, double) inside EDT?
Please advise!
Details:
Clicking a Swing GUI button, my program triggers a time-consuming task.
Basically, it reads a (large) file with pair-values (date, double) and then shows them by using the JFreeChart framework.
Because this is a time-consuming task, while reading and displaying data, a JProgreessBar shows user the progress status in foreground, while the chart is updated in background (user is still able to visually see every chart update, behind the progress bar).
This worked fine, until I decided to review the code to have my chart data being updated and displayed inside Swing EDT. Then, a complete task that usually took about 7 minutes to finish, started to take several hours to complete!
Here’s the list of threads I’m using:
1) Since the task is triggered by a Swing Button Listener, it is running in EDT. The JProgressBar is also running in this same thread;
2) While showing the JProgressBar, a second (“normal”) thread is created and executed in the background. This is where the heavy work is done.
It includes the update of the JProgressBar status on the other thread (by calling JProgressBar.setvalue()) and the update of my JFreeChart chart (by calling TimeSeries.addOrUpdate(date, double), which automatically updates a org.jfree.chart.ChartPanel).
Updating the chart in my second (“normal”) thread usually took about 7 minutes to finish. Without any noticeable issue.
However, knowing that most Swing object methods are not "thread safe" and ChartPanel is just a Swing GUI component for displaying a JFreeChart object, I decided to run my chart update code TimeSeries.addOrUpdate(date, double) inside EDT.
Still running in my second “normal” thread, I tested with the following asynchronous code:
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
TimeSeries.addOrUpdate(date, double);
}
});
but I realized my JProgressBar would reach 100% much before the chart was updated.
I guess this was expected as displaying chart data is much slower than getting and processing the data.
I then tried following synchronous code:
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
TimeSeries.addOrUpdate(date, double);
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
And this is where I found the performance issue: now a complete task that used to take about 7 minutes to finish, started to take hours to complete!
So, my question is:
What am I doing wrong? Did I misunderstood the Swing Concurrency lesson? Do I really have to run TimeSeries.addOrUpdate(date, double) inside EDT?
Please advise!
UPDATE:
The complete code would be too large to show here, but you can find a code snapshot below.
Perhaps, the only thing noticeable about the code is that I use Reflection. This is because I use a generic ProgressBar Class that invokes in background whatever class I send it as an argument (though this is not clearly shown in the snapshot below).
//BUTTON LISTENER (EDT)
public void actionPerformed(ActionEvent arg0) {
new Process_offline_data();
}
public Process_offline_data() {
//GET DATA
String[][] data = get_data_from_file();
//CREATE PROGRESS BAR
int maximum_progressBar = data.length;
JProgressBar jpb = init_jpb(maximum_progressBar);
//JDIALOG MODAL WINDOW
JDialog jdialog = create_jdialog_window(jpb);
Object class_to_invoke_obj = (Object) new Show_data_on_chart();
String main_method_str = "do_heavy_staff";
Runnable r = new Runnable() {
public void run() {
//REFLECTION
Method method = null;
try {
method = class_to_invoke_obj.getClass().getDeclaredMethod(main_method_str, JProgressBar.class, String[][].class);
} catch (NoSuchMethodException | SecurityException e1) {
e1.printStackTrace();
jdialog.dispose(); //UNBLOCKS MAIN THREAD
return;
}
try {
method.invoke(class_to_invoke_obj, jpb, data);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
e1.printStackTrace();
jdialog.dispose(); //UNBLOCKS MAIN THREAD
return;
}
//----------------
jdialog.dispose(); //UNBLOCKS MAIN THREAD
}
};
new Thread(r).start();
//----------------
//THIS IS STILL EDT
jdialog.setVisible(true); //BLOCKS HERE UNTIL THE THREAD CALLS jdialog.dispose();
}
public class Show_data_on_chart {
public void do_heavy_staff(JProgressBar jpb, String[][] data) {
TimeSeries time_series = get_TimeSeries(); //JFreeChart datamodel
int len = data.length;
for (int i=0; i<len; i++) {
jpb.setValue(i+1);
Millisecond x_axys_millisecond = convert_str2date(data[i][0]);
Double y_axys_double = convert_str2double(data[i][1]);
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
//AUTOMATICALLY UPDATES org.jfree.chart.ChartPanel
time_series.addOrUpdate(x_axys_millisecond, y_axys_double);
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}
}
}
This is how i solved the problem of updating the chart.
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYSeries;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
import org.jfree.chart.plot.XYPlot;
import java.lang.reflect.InvocationTargetException;
import javax.swing.SwingUtilities;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
public class App extends ApplicationFrame {
XYSeries sin = new XYSeries("Sin");
public App(String applicationTitle, String chartTitle) {
super(applicationTitle);
JFreeChart xylineChart = ChartFactory.createXYLineChart(chartTitle, "X", "Y", new XYSeriesCollection(sin),
PlotOrientation.VERTICAL, false, true, false);
ChartPanel chartPanel = new ChartPanel(xylineChart);
chartPanel.setPreferredSize(new java.awt.Dimension(560, 367));
final XYPlot plot = xylineChart.getXYPlot();
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, false);
plot.setRenderer(renderer);
setContentPane(chartPanel);
}
public Runnable r = new Runnable() {
double x, y;
int i;
public void run() {
int steps = 69999;
for (i = 0; i < steps; i++) {
//sample plot data
x = Math.PI * 2.0 * 10.0 / ((double) steps) * ((double) i);
y = Math.sin(x);
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
if ((i % 1000) == 0) {
//adding data and redrawing chart
sin.addOrUpdate(x, y);
} else {
//adding point without redrawing of the chart
sin.add(x, y, false);
}
}
});
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//redrawing chart if all data loaded
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
sin.fireSeriesChanged();
}
});
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
public Runnable rupdate = new Runnable() {
public void run() {
while (true) {
//redrawing chart
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
sin.fireSeriesChanged();
}
});
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
//waiting for next update
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
public static void main(String[] args) {
final App chart [] = new App[1];
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
chart[0] = new App(null, null);
chart[0].pack();
RefineryUtilities.centerFrameOnScreen(chart[0]);
chart[0].setVisible(true);
}
});
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread job = new Thread(chart[0].r);
job.start();
Thread job2 = new Thread(chart[0].rupdate);
job2.start();
}
}
The above code includes two solutions. You can use either of them or both. Chart can be updated during data feeding. For example every 100th point and after last poit. Eventually you can make external thread that updates chart after some time. I have used updateAndWait every time instead of updateLater.
In your code do not use reflections like that. You should make interface. For example:
public interface IHardWork {
public void do_heavy_staff(JProgressBar jpb, String[][] data);
}
and implement it on every object that do the work:
public class Show_data_on_chart implements IHardWork {
public void do_heavy_staff(JProgressBar jpb, String[][] data) {
// TODO Auto-generated method stub
}
}
then use it:
IHardWork hwObj = new Show_data_on_chart();
hwObj.do_heavy_staff(jpb, data);
hwObj = new OtherHWObj();
hwObj.do_heavy_staff(jpb, data);
Eventualy You can make a base class for it and use polymorphism.
class class1{
public class1(){//here is my GUI commants}
#Override
public void actionPerformed(ActionEvent evt) //this is my action performed from a jframe window
{
worker = new SwingWorker<Void, Void>(){//ia m creating a worker
protected WaitWindow waitWindow;
#Override
protected Void doInBackground() throws Exception {
waitWindow= new WaitWindow();//i call waitWindow class to pop up my new window with the progressBar
return null;
}
#Override
protected void done(){
waitWindow.CloseWaitWindow();
}
};
try{
String option = (String)serversList.getSelectedItem();
if (evt.getSource().equals(Button1))//when client presses button1
{
if(option.equals("icsd Server"))
{//here is my connection
Registry registry = LocateRegistry.getRegistry("localhost",1080);
icsdserver = (ICSDinterface)registry.lookup("RmiCheckICSD");
worker.execute(); //i am calling execute until the server return 0 this might take a long time
if (icsdserver.RequestForEntry("icsd",0)==0)
{
worker.cancel(true); //when server tell its all ok (with 0) i call cancel(true)
AddGrade d = new AddGrade(icsdserver,"icsd");
}
}
}
}
catch (RemoteException ex) {System.out.println(ex);}
catch (NotBoundException ex) {System.out.println(ex);}
}}
The Wait Window class follows
class WaitWindow extends JFrame //my WaitWindow Class
{
private JProgressBar bar ;
public WaitWindow(){
super("Wait Until Connection Is ready");
setSize(100,200);
bar = new JProgressBar();
bar.setIndeterminate(true);
bar.setPreferredSize(new Dimension(300,330));
add(bar);
getContentPane();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void CloseWaitWindow()
{
removeNotify();
}
}
What am I doing wrong here? I want the wait Window to shown until server's RequestForEntry method return 0 this might take some time. Also there is no error with RMI connection.
You're blocking the Event Dispathing Thread, with the call to RequestForEntry, which should be within the doInBackground method of the SwingWorker, for example
public void actionPerformed(ActionEvent ev) //this is my action performed from a jframe window
{
try {
final String option = (String) serversList.getSelectedItem();
if (evt.getSource().equals(Button1))//when client presses button1
{
final WaitWindow waitWindow = new WaitWindow();
worker = new SwingWorker<Void, Void>() {//ia m creating a worker
#Override
protected Void doInBackground() throws Exception {
if (option.equals("icsd Server")) {//here is my connection
Registry registry = LocateRegistry.getRegistry("localhost", 1080);
icsdserver = (ICSDinterface) registry.lookup("RmiCheckICSD");
worker.execute(); //i am calling execute until the server return 0 this might take a long time
if (icsdserver.RequestForEntry("icsd", 0) == 0) {
worker.cancel(true); //when server tell its all ok (with 0) i call cancel(true)
AddGrade d = new AddGrade(icsdserver, "icsd");
}
}
return null;
}
#Override
protected void done() {
waitWindow.CloseWaitWindow();
}
};
}
} catch (RemoteException ex) {
System.out.println(ex);
} catch (NotBoundException ex) {
System.out.println(ex);
}
}
Swing is a single threaded framework and isn't thread safe. This means that anything the blocks the Event Dispatching Thread will prevent it from processing new events, including paint requests.
Swing components should also only be updated from within the context of the EDT, which is where SwingWorker comes in.
See Concurrency in Swing and Worker Threads and SwingWorker for more details
I have a piece of JFrame code, which stops a SwingWorker when it is closed:
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;
/**
*
* #author yccheok
*/
public class JavaApplication11 extends JFrame {
public JavaApplication11() {
this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
final Task task = new Task();
task.execute();
addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
if (task != null) {
task.cancel(true);
}
}
});
}
public class Task extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() {
for (int i = 0; i < 1000; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println("interrupted in doInBackground");
break;
}
System.out.println("-> " + i);
}
return null;
}
#Override
public void done() {
System.out.println("DONE!!!");
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new JavaApplication11().setVisible(true);
}
}
However, randomly, I realize when I close the JFrame, SwingWorker's done method is executed before doInBackground is finished. (You need to execute the above JFrame several times in order to produce the problem)
-> 0
-> 1
-> 2
-> 3
-> 4
DONE!!!
interrupted in doInBackground
May I know why is it so?
From Howard's comment, http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6826514 shows this may be a bug.
I've run in to this as well. I tend to put cleanup inside doInBackground, if it's order-dependent, and only use done for exception handling.
#Override
protected Void doInBackground() {
try {
// ...
} finally {
// some cleanup inside 'doInBackground'
if (isCancelled()) {
// ...
} else {
// ...
}
}
return (Void) null;
}
#Override
protected void done() {
try {
get();
} catch (CancellationException x) {
// ...
} catch (InterruptedException x) {
// ...
} catch (ExecutionException x) {
// ...
}
}
(Remember to use invokeLater if you need to update the GUI from doInBackground.)
In my case, I had something like this:
doInBackground performing an "open file" routine, creating Swing components periodically and adding them to the GUI.
On cancellation (via a progress bar dialog with a Cancel button), done would remove all the components created during doInBackground.
Sometimes these actions would overlap, and doInBackground would continue creating components after done had performed the wipe. To the user, it would look like pressing Cancel simply did not work occasionally, except that debug showed that done was being called. There was no other explanation, except this behavior of SwingWorker.
In my GUI I have a PDF file creation operation. The operation can take up to 10-15 seconds to complete. When I start the operation, I attach a listener to it. The listener changes the cursor and disables the GUI, until the operation completes.
I would also like to add a progressbar, so the users will have a idea when it is going to complete.
Created a method startProgressBar() and called it from the start of the operation method.
See Below:
private void startSavePdfOperation() {
startProgressBar();
saveOp = new AplotSaveOperation(appReg.getString("aplot.message.SAVETOPDF"), "PDF", session);
saveOp.addOperationListener(new MyOperationListener(this) {
startProgressBar Method - See Below:
public void startProgressBar() {
Shell shell = new Shell(getShell());
shell.setSize(260, 120);
final ProgressBar bar = new ProgressBar(shell, SWT.SMOOTH);
bar.setBounds (20, 20, 200, 20);
shell.open();
final int maximum = bar.getMaximum();
new Thread(new Runnable() {
public void run() {
for (final int[] i = new int[1]; i[0] <= maximum; i[0]++) {
try {Thread.sleep (100);} catch (Throwable th) {}
if (Display.getDefault().isDisposed()) return;
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if (bar.isDisposed ()) return;
bar.setSelection(i[0]);
}
});
}
}
}).start();
The code above created the ProgressBar. The issue is that the operation would end well before the progressbar indicator was close to ending.
Question: Is this because in the method I am creating a new thread and the indicator is updating according to the new thread and not the operation thread?
Question: Is it possible to create a new thread that watches the GUI thread and updates the progressbar accordingly?
Read a article suggesting using ProgressMonitorDialog with IRunnableWithProgress.
Method startProgressBar using ProgressMonitorDialog - see below:
public void startProgressBar() {
ProgressMonitorDialog dialog = new ProgressMonitorDialog(getShell());
try {
dialog.run(true, true, new IRunnableWithProgress(){
public void run(IProgressMonitor monitor) {
monitor.beginTask("Some nice progress message here ...", 100);
** getThread(); **
monitor.done();
}
});
}
catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void getThread() {
new Thread etc.. etc...
}
It seems that it will have the same issues with threading and updating as the code above.
Question: So now I am thinking can I just add or update the ProgressBar to my existing Listener
OperationListener Code - see below:
public abstract class MyOperationListener implements InterfaceAIFOperationListener {
AplotCreatePDFDialog w = null;
public MyOperationListener(AplotCreatePDFDialog win) {
w = win;
}
public void startOperation(String startMessage) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
w.recursiveSetEnabled(getShell(), getShell().getEnabled());
w.getShell().setEnabled(!getShell().getEnabled());
}
});
}
public void endOperation() {
try {
endOperationImpl();
}
finally {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
w.recursiveSetEnabled(getShell(), true);
w.getShell().setEnabled(!getShell().getEnabled());
w.close();
}
});
}
}
abstract protected void endOperationImpl();
} // end class MyOperationListener
Thanks for any help you can give me with this.
EDIT
Baz, your answer below is exactly what the question asked, so thank you for answering.
But I am starting to think that what I am trying to do is not possible.
When my operation starts, I wanted the progress bar indicator to start and when my operation ended I wanted the indicator be at the end and the monitor would close.
I thought there might bee a way to use my listener to add the progressbar. Something like the following.
public void startOperation(String startMessage) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
->monitor.beginTask("Creating PDF File(s)", IProgressMonitor.UNKNOWN);<-
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
w.recursiveSetEnabled(getShell(), getShell().getEnabled());
w.getShell().setEnabled(!getShell().getEnabled());
}
});
}
public void endOperation() {
try {
->monitor.worked(1);<-
endOperationImpl();
}
finally {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
w.recursiveSetEnabled(getShell(), true);
w.getShell().setEnabled(!getShell().getEnabled());
->monitor.done();<-
w.close();
}
});
}
}
abstract protected void endOperationImpl();
} // end class MyOperationListener
But I am starting to see that the ProgressBar has to have some sort of measurement to display the indicator correctly.
I would be happy if the indicator just went back and forth and the monitor would close at the end of the operation.
Why not use ProgressMonitorDialog?
Here is a related answer from me showing a simple example.
This is what it looks like:
If you are not sure about the workload, use this code:
monitor.beginTask("Copying files", IProgressMonitor.UNKNOWN);
It will show the idle bar while running.