I'm experiencing a following problem. I have designed a GUI in implemented Netbeans GUI builder and I've got several buttons in my program. If I press one of the button it will start running some method that takes about 10 seconds, but there is also a button for cancelling running this method. But while the Button 1 method is running I can not click on any other button in my program, it's like being freezed and I have to wait until the method is done.
I think this has something to do with multithreading, can you guys give me a hint ??
Thanks !
You can use SwingWorker.
public class MyBackgroundWorker extends SwingWorker<Integer, String> {
#Override
protected Integer doInBackground() throws Exception {
callYourLongTimeTakingMethod();
return 0;
}
}
Now on your Start button event listener create an object for this SwingWorker class and execute it.
objMyBGWorker = new MyBackgroundWorker();
objMyBGWorker.execute();
And on your cancel button even listener you can call,
objMyBGWorker.cancel(true);
Related
I'm using POI in a function to fill the content of my excel document (it takes 10 seconds) and when i call my function I want to use a JProgressBar to see the progress, but the button and the program is block, i need to to make in other thread? and how can I do it? an example of my code:
btnEjecutar.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
//the function
generarDocumento(nombre);
}
Try to use an invokeLater, like the example bellow:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
generarDocumento(nombre);
});
Event listeners are executed in the UI thread. If an event listener takes a long time, the UI will stop working/lock up/block/hang.
My guess is that the method generarDocumento() takes a long time. If you want the UI to continue working, you must run it in a worker thread. The Java documentation contains several examples how to do that: https://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
The last example in the tutorial contains demo code how to update a progress bar: https://docs.oracle.com/javase/tutorial/displayCode.html?code=https://docs.oracle.com/javase/tutorial/uiswing/examples/components/ProgressBarDemoProject/src/components/ProgressBarDemo.java
Note: The linked content is copyrighted; therefore I can't copy it here.
I am executing several SQL queries in the function evoked by a button in java. I wish to show the status of the same, and I am using a jProgressBar for the same. But the problem is it will only update after the button has finished executing itself, making it pointless to show the progress. How can I display the actual progress of the executing button.
Make a thread dispatcher like this
public class ThreadDispatcher implements Runnable {
public ThreadDispatcher() {
}
public void run() {
//call the method related to query here
}
}
When button pressed call this class and let this class evoke your query related function.
It may be like this when you press the button.
Thread thread = new Thread(new ThreadDispatcher());
thread.start();
sleep(100);
catch the InterruptedException ex.
Link for Thread example
You need to do the computation on a background thread, not the main thread.
Take a look at the Java SwingWorker Tutorial.
I have written following code.I have not shown full source but psudo code.
class UI extends JFrame
{
//created UI with one Button
onButtonclick()
{
//did some operation before set icon to button
//say opened fileopen dialog and get file
button.setText("");
ImageIcon progressbar = new
ImageIcon(DatasetExporterUI.class.getResource("/progreassbar.gif"));
buttonExport.setIcon(progressbar);
// did some database operations
//again removed icon from button
button.setIcon(null);
button.setText("click");
}
}
When I click on button It opens file open dialog and and button text get set to empty.
But It doesn't set Icon to button.When all Database operation are done which are performed after Icon set to button that time Icon is appeared on button.
Why this behavior is?
How to set Icon to button and do some Database operations and again remove it?
Thank you. :)
The GUI system can only do one thing at a time, like most code (except for code that uses threads). Calling your listener is a thing. The GUI system cannot do anything else while your listener is running.
Your database operation needs to run on another thread (which you can create) and then update the GUI when it's done. Something like this:
void onButtonPressed() {
// The code to open the file dialog goes here
button.setText("");
ImageIcon progressbar = new
ImageIcon(DatasetExporterUI.class.getResource("/progreassbar.gif"));
buttonExport.setIcon(progressbar);
new Thread() {
#Override
public void run() {
// do some database operations here
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
//again remove icon from button
button.setIcon(null);
button.setText("click");
}
});
}
}.start();
}
Code in different threads runs at the same time. This is convenient but dangerous. Be extremely careful when accessing data from the new thread - if one thread changes a field and the other thread reads it, the results might not be what you expect. The simplest thing to do is to make sure the main thread doesn't change any variables used by the new thread while it's running.
When your database operations are finished, you can't set the button back to normal by just calling setText. Only the main thread is allowed to affect the GUI - what if the main thread was drawing the button on the screen at the same time the database operation thread was changing the text? The button might be drawn incorrectly. So you need to call EventQueue.invokeLater which tells the GUI system to run your code in the near future when it's not busy. The code inside new Runnable() {} is like the code in the button listener - no other GUI-related code will run while it does.
This should work:
Image progressbar= ImageIO.read(DatasetExporterUI.class.getResource("/progreassbar.gif"));
buttonExport.setIcon(new ImageIcon(progressbar));
I am using eclipse's jobs API to run big task as a job, once task is completed I am setting boolean variable to true and if that variable is true I am executing WizardDialog in UI thread. My current code looks like this:
Job longRunningJob = new Job("Long running job...") {
#Override
protected IStatus run(IProgressMonitor monitor) {
boolean shouldShowDialog = doLongRunningJob();
if(shouldShowDialog) {
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
//Will open wizard dialog here
WizardDialog wizardDialog = new WizardDialog(Display.getCurrent().getActiveShell(), new TestWizard());
wizardDialog.setBlockOnOpen(true);
wizardDialog.open();
}
});
}
}
}
longRunningJob.setUser(true);
longRunningJob.schedule();
My problem is run inside Display thread not executing in reliable way, means sometime it goes inside run method where as sometimes it doesn't, I tried putting breakpoint inside run method and testing it out but same happens.
My question is, is what I am doing is correct way? Is this expected behaviour? So how do I handle this scenario ie once shouldShowDialog is true how do I execute code inside Display thread?
Edit: One behaviour I observed while debugging is dialog gets displayed but suddenly it get closes, I think it's exiting the thread.
The problem with disappearing dialogs is most commonly caused by using currently active Shell as the parent for the dialog. E.g. if there is a ProgressDialog open when you create your dialog then that other dialog will be the parent of your dialog. And when the other dialog closes, so does yours.
Instead, use something like:
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
I have an applet that calls a JDialog that contains a JProgressBar component. I subclass the JDialog to expose a method to update the JProgressBar, something like:
public class ProgressDialog extends javax.swing.JDialog {
public void setProgress(double progress) {
jProgressBar1.setValue(jProgressBar1.getMinimum() + (int) (progress * jProgressBar1.getMaximum()));
}
...
}
I use this dialog in the following manner:
public void test() throws Exception {
progressDialog = new ProgressDialog(null, true);
try {
progressDialog.setLocationRelativeTo(null);
// show the dialog
EventQueue.invokeLater(new Runnable() {
public void run() {
progressDialog.setVisible(true);
}
});
// business logic code that calls progressDialog.setProgress along the way
doStuff();
} finally {
progressDialog.setVisible(false);
progressDialog.dispose();
}
}
It works fine on Windows/any browser. However, when invoking the above function on Firefox 2/3/3.5 on a Mac, the progressDialog is displayed indefinitely, i.e. it doesn't close.
I suspected that calling setVisible(true) inside the EventQueue was causing the problem, since it's a blocking call and might block the queue completely, so I tried changing it to:
// show the dialog
new Thread() {
public void run() {
progressDialog.setVisible(true);
}
}.start();
With this change, the progressDialog now closes correctly, but a new problem emerged - the contents of the dialog (which included the progressbar, an icon and a JLabel used to show a message string) were no longer shown inside the dialog. It was still a problem only on Mac Firefox.
Any ideas? I realize it's probably some AWT threading issue, but I've been at this for a couple of days and can't find a good solution. Wrapping the doStuff() business logic in a separate new Thread seems to work, but it's not easy to refactor the actual business logic code into a separate thread, so I'm hoping there's a simpler solution.
The envt is:
Mac OSX 10.5
Java 1.5
Firefox 2/3/3.5
Found out that the problem was that the applet function was executing inside the AWT dispatcher thread, therefore the thread blocks and no events are processed until the applet function finishes execution.
Solution was to move the processing logic into a separate thread spawned by the ProgressDialog object before calling setVisible(true). setVisible(true) would block the main thread but still allow the event dispatcher to continue processing, hence rendering the contents of the dialog until the spawned thread calls setVisible(false) to hide the dialog.