How to make thread wait untill method of another class completes - java

Here is my example code:
package javaapplication35;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import static javaapplication35.ProgressBarExample.customProgressBar;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
public class ProgressBarExample {
final static JButton myButton =new JButton("Start");
final static JProgressBar customProgressBar = new JProgressBar();
private static final JPanel myPanel = new JPanel();
public static void main(String[] args) {
customProgressBar.setMaximum(32);
customProgressBar.setStringPainted(true);
myPanel.add(customProgressBar);
myPanel.add(myButton);
myButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
Thread firstly =new Thread(new Runnable (
) {
#Override
public void run() {
Calculations a = new Calculations();
a.doCaculations();
}
});
Thread secondly =new Thread(new Runnable (
) {
#Override
public void run() {
JOptionPane.showMessageDialog(null,"just finished");
}
});
firstly.start();
try {
firstly.join();
} catch (InterruptedException ex) {
Logger.getLogger(ProgressBarExample.class.getName()).log(Level.SEVERE, null, ex);
}
secondly.start();
}
});
JOptionPane.showMessageDialog(null, myPanel, "Progress bar test", JOptionPane.PLAIN_MESSAGE);
}
}
class Calculations {
public void doCaculations() {
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
int value = 0;
while (value < customProgressBar.getMaximum()) {
Thread.sleep(250);
value ++;
customProgressBar.setValue(value);
}
return null;
}
}.execute();
}
private void doOtherStaff(){
//more methods, that don't need to run in seperate threads, exist
}
}
There are 2 Threads.
The firstly thread creates a Calculations class insance and then runs a doCaculations() method on it.
The secondly thread pops-up a message.
The doCaculations() method in my "real" code performs some time consuming maths and in order to simulate the time spent I added that Thread.sleep(250);. I need to inform the user on the progress of the calculations so I am using the progressbar, that is updated by the doCaculations() method.
I am trying to make the code work in a way that the secondly thread runs after the firstly thread finishes. But I cannot make it work. What happens is that the pop-up message pops-up immediately (and that means that it's thread run before I want it to run).
Note:The "just finished" message is there just to test the code. In my "real" program a method would be in it's place. I am making this note because if I just wanted a message to show I could just place it in the end of the doCaculations() method, and everything would work fine.
I know I must be doing wrong with the Thread handling but I cannot find it. Any ideas?
PS: A thought: Actually the doCaculations() method has its own thread. So it runs "in a SwingWorker inside a Thread". Iguess the firstly.join(); works correctly. But after the doCaculations() method is called the fistrly thread is considered finished, and that's why the code goes on with the secondly thread, not knowing that the doCaculations() thread is still doing something.

In java you can use swingworker and in the done() method call your Dialog
In android you can use AsyncTask for calling the new thread and in the OnPostExecute method, call show message dialog.

Try
a.doCaculations();
a.join();
edit:
Since you are using SwingWorker my previous answer is incorrect, but, as in you comment, you've extended Thread, the following should work for you:
Thread a = new Calculations();
a.start();
a.join();
Don't forget, that you have to override run method in Calculations class, like:
class Calculations extends Thread {
#Override
public void run() {
//your code here
}
}

Your Calculations class must extend SwingWorker. You do your calculations in doInBackground()
public class Calculations extends SwingWorker<Void, Void>{
#Override
protected Void doInBackground() throws Exception {
System.out.println("Calculating.");
Thread.sleep(3000);
return null;
}
}
And in your actionPerformed() you use Calculations like this.
public void actionPerformed(ActionEvent e)
{
//FISRT run method
Calculations a = new Calculations();
a.execute(); // Start calculations
try {
a.get(); // Wait for calculations to finish
} catch (InterruptedException | ExecutionException e1) {
e1.printStackTrace();
}
//THEN inform that just finished
JOptionPane.showMessageDialog(null,"just finished");
}
EDIT: If you have multiple methods that you would like to run in a SwingWorker you can keep your code almost like it is. But only add these lines.
public class Calculations{
protected void calculate() {
SwingWorker sw = new SwingWorker(){
#Override
protected Object doInBackground() throws Exception {
System.out.println("Calculating.");
Thread.sleep(3000);
return null;
}
};
sw.execute(); //Start
try {
sw.get(); //Wait
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
In each method of Calculations you create a new SwingWorker like you did and wait for it to finish by calling SwingWorker.get();

Related

Query on creating separate thread in java?

Below is the compiled program replica of actual problem code,
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class Dummy {
public static boolean getUserCheck(int size, boolean Check) {
if (Check) {
int ret = JOptionPane.showConfirmDialog(null, size + " entries, Yes or no?",
"Warning", 0);
if (ret > 0) {
System.out.println("User said No: " + ret);
return false;
} else if (ret <= 0) {
System.out.println("user said Yes: " + ret);
return true;
}
}
return true;
}
public static void workerMethod1() {
System.out.println("am worker method 1");
}
public static void workerMethod2() {
System.out.println("am worker method 2");
}
public static void main(String[] args) {
System.out.println("mainthread code line 1");
int size = 13;
boolean thresholdBreach = true;
if (getUserCheck(size, thresholdBreach)) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
workerMethod1();
}
});
SwingUtilities.invokeLater(new Runnable() {
public void run() {
workerMethod2();
}
});
}
System.out.println("mainthread code line 2");
System.out.println("mainthread code line 3");
}
}
where i would like to run the if{} block in main() on separate thread. Because these 2 lines,
System.out.println("mainthread code line 2");
System.out.println("mainthread code line 3");
need not wait for completion of if(){} block
Another problem is, experts recommend to run confirm-dialog methods on event thread.
int ret = JOptionPane.showConfirmDialog(null, size + " entries, Yes or no?",
"Warning", 0);
Please help me!!!!
JOptionPane is a Swing method and should be called on the EDT, the Event Dispatch Thread, and only on this thread, and so it suggests that all your code above should be on the EDT, and that most of your SwingUtilities.invokeLater(new Runnable() calls are completely unnecessary. The only necessary ones will be the main one, where you launch your Swing GUI code, and any areas where Swing calls need to be made from within background threads. Again, if any of the above code is being made within background threads, then the JOptionPane should not be in that thread.
For more specific information in this or any other answer, please provide more specific information in your question. Let's end all confusion. The best way to get us to fully and quickly understand your problem would be if you were to to create and post a minimal example program, a small but complete program that only has necessary code to demonstrate your problem, that we can copy, paste, compile and run without modification.
I have a sneaking suspicion that a decent refactoring along MVC lines could solve most of your problems. Your code is very linear with its lines of code that must follow one another and its if blocks, and it is also tightly coupled with your GUI, two red flags for me. Perhaps better would be less linear code, more event and state-driven code, code where your background code interacts with the GUI via observer notification, and where the background code likewise responds to state changes in the GUI from control notification.
Your control needs two SwingWorkers, one to get the row count and the other to get the rest of the data if the user decides to do so. I'd add a PropertyChangeListener to the first SwingWorker to be notified when the row count data is ready, and then once it is, present it to the view for the user to select whether or not to proceed. If he decides to proceed, I'd then call the 2nd SwingWorker to get the main body of the data.
For example, a rough sketch of what I'm talking about:
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
#SuppressWarnings("serial")
public class SwingWorkerFooView extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 300;
private JProgressBar progressBar;
private JDialog dialog;
public SwingWorkerFooView() {
add(new JButton(new ButtonAction("Foo", this)));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public boolean showOptionGetAllData(int numberOfRows) {
String message = "Number of rows = " + numberOfRows + ". Get all of the data?";
String title = "Get All Of Data?";
int optionType = JOptionPane.YES_NO_OPTION;
int result = JOptionPane.showConfirmDialog(this, message, title, optionType);
return result == JOptionPane.YES_OPTION;
}
public void showProgressBarDialog() {
progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
Window window = SwingUtilities.getWindowAncestor(this);
dialog = new JDialog(window, "Hang on", ModalityType.APPLICATION_MODAL);
JPanel panel = new JPanel();
panel.add(progressBar);
dialog.add(panel);
dialog.pack();
dialog.setLocationRelativeTo(this);
dialog.setVisible(true);
}
public void closeProgressBarDialog() {
dialog.dispose();
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SwingWorkerFoo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SwingWorkerFooView());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class ButtonAction extends AbstractAction {
Workers workers = new Workers();
private SwingWorker<Integer, Void> firstWorker;
private SwingWorker<List<String>, Void> secondWorker;
private SwingWorkerFooView mainGui;
public ButtonAction(String name, SwingWorkerFooView mainGui) {
super(name);
this.mainGui = mainGui;
}
#Override
public void actionPerformed(ActionEvent e) {
firstWorker = workers.createFirstWorker();
firstWorker.addPropertyChangeListener(new FirstPropertyChangeListener());
firstWorker.execute();
mainGui.showProgressBarDialog();
}
private class FirstPropertyChangeListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
mainGui.closeProgressBarDialog();
try {
int numberOfRows = firstWorker.get();
boolean getAllData = mainGui.showOptionGetAllData(numberOfRows);
if (getAllData) {
secondWorker = workers.createSecondWorker();
secondWorker.addPropertyChangeListener(new SecondPropertyChangeListener());
secondWorker.execute();
mainGui.showProgressBarDialog();
} else {
// user decided not to get all data
workers.cleanUp();
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
private class SecondPropertyChangeListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
mainGui.closeProgressBarDialog();
try {
List<String> finalData = secondWorker.get();
// display finalData in the GUI
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
}
class Workers {
// database object that may be shared by two SwingWorkers
private Object someDataBaseVariable;
private Random random = new Random(); // just for simulation purposes
private class FirstWorker extends SwingWorker<Integer, Void> {
#Override
protected Integer doInBackground() throws Exception {
// The Thread.sleep(...) is not going to be in final production code
// it's just to simulate a long running task
Thread.sleep(4000);
// here we create our database object and check how many rows there are
int rows = random.nextInt(10 + 10); // this is just for demonstration purposes only
// here we create any objects that must be shared by both SwingWorkers
// and they will be saved in a field of Workers
someDataBaseVariable = "Fubar";
return rows;
}
}
private class SecondWorker extends SwingWorker<List<String>, Void> {
#Override
protected List<String> doInBackground() throws Exception {
// The Thread.sleep(...) is not going to be in final production code
// it's just to simulate a long running task
Thread.sleep(4000);
List<String> myList = new ArrayList<>();
// here we go through the database filling the myList collection
return myList;
}
}
public SwingWorker<Integer, Void> createFirstWorker() {
return new FirstWorker();
}
public void cleanUp() {
// TODO clean up any resources and database stuff that will not be used.
}
public SwingWorker<List<String>, Void> createSecondWorker() {
return new SecondWorker();
}
}
The key to all of this is to not to think in a linear console program way but rather to use observer design pattern, i.e., listeners of some sort to check for change of state of both the GUI and the model.
It's essentially:
create worker
add observer to worker (property change listener)
execute worker
show progress bar dialog or notify user in some way that worker is executing.
The listener will be notified when the worker is done, and then you can query the worker (here via the get() method call) as to its end result.
Then the progress dialog can be closed
And the view can display the result or get additional information from the user.
Yes; SwingUtilities.invokeLater() simply places your runnable on the AWT event queue to be processed later, and it is safe to do so at any time.

Error handling in SwingWorker

My question is a theory-based question, but it does meet a specific need I have.
What do you do when your SwingWorker throws an Exception that you a) can anticipate and b) need to recover from and continue, but you want to notify the user that this error has happened? How do you grab the expected exception and notify the user without violating the "No Swing code from doInBackground()" rule?
I have, in consideration of this problem, developed a SSCCE that I would like to put forth with the questions below it.
SSCCE:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutionException;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Test {
public static void main(String args[]) {
final JFrame frame = new JFrame();
JButton go = new JButton("Go.");
go.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Task(frame);
}
});
frame.add(go);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
static class Task extends SwingWorker<Void, Void> {
JFrame parent;
JDialog dialog;
public Task(JFrame parent) {
this.parent = parent;
dialog = new JDialog(parent);
JProgressBar jpb = new JProgressBar();
jpb.setIndeterminate(true);
dialog.add(jpb);
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
execute();
}
#Override
protected Void doInBackground() throws Exception {
for(int i = 0; i < 100000; i++) {
System.out.println(i);
try {
if(i == 68456) throw new IllegalStateException("Yikes! i = 68456.");
} catch (final IllegalStateException e) {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
JOptionPane.showMessageDialog(parent, "Error: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
});
}
}
return null;
}
#Override
protected void done() {
if (!isCancelled()) {
try {
get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("done");
dialog.dispose();
}
}
}
Is it valid to call SwingUtilities.invokeAndWait() within the doInBackground() method? I did some Thread profiling on this and the results were thus:
Once the "Go" button is pressed, the SwingWorker-pool-1-thread-1 thread goes Green. THEN, when the if condition is met, the error is thrown, and the error dialog is displayed, the thread goes yellow, and there is indeed a green "blip" on the AWT-EventQueue-0 thread, indicating that the EDT was invoked. I waited about 10 seconds, pressed "ok," and the SwingWorker thread went green again.
Are there any potential pitfalls to doing something like this? Does anyone have experience with notifying users of computation errors in real time from the SwingWorker?
I'll be honest, this approach has me leery. It seems unorthodox but I cannot say for certain whether this is a bad idea.
I see no problem with using invokeAndWait() when the user actually needs to approve. If not, as shown in this example, a SwingWorker<Void, String> can simply call publish() with data and error messages interleaved. A suitable message appended in done() would allow the user to review the accumulated output if necessary.

SwingWorker's done method executes even before doInBackground is finished, randomly

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.

Child thread not starting

I have created a GUI for starting a Thread which does something very simple. However, the child thread never starts.
The child thread, if started, will give some output; I don't get any output though. What am I missing?
Here's the Code:
The GUI class:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class gui {
public static void main(String [] args) {
//final standalone s = new standalone();
final try2 t= new try2();
JFrame win = new JFrame();
win.setLayout(new FlowLayout());
JButton start = new JButton("Start");
JButton stop = new JButton("Stop");
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
t.t.start();
System.out.println("M on!");
try{
Thread.currentThread().sleep(10000);
}catch(Exception e1)
{
e1.printStackTrace();
}
System.out.println("M off!");
if(t.t.isInterrupted())
System.out.println("Stopped");
}
});
win.add(start);
win.add(stop);
win.setVisible(true);
}
}
And here is the Child Thread
public class try2 implements Runnable {
public Thread t;
int i;
try2() {
t=new Thread();
}
public void run() {
System.out.println(++i);
}
}
When you call t.t.start() it is starting the thread object in the t field of your try2 object. Unfortunately, this Thread has no Runnable, so when you start it, it will exit immediately. The try2.run() method is not called because the thread knows nothing about it.
Your code is convoluted. I'd simplify / fix it as follows:
Get rid of the try2.t field.
In the actionPerformed method create and run the thread as follows:
new Thread(t).start();
where t is your try2 instance.
And while you are fixing the code, try2 violates all Java style guides that I've ever come across. Class names should always start with a capital letter. Get into the habit of doing it right ...
Make your class try2 extends Thread (and remove the implements Runnable)., then simply call start() on your try2 instance.
Your class try2 should extend Thread (and implement the method run())
The way you are dealing with it, yuo are calling the run()-method of the thread-Object t inside try2. But the run()-method of this object is empty.

how to pause program until a button press?

i use from a class that extended from jframe and it has a button(i use from it in my program)
i want when run jframe in my program the whole of my program pause
until i press the button.
how can i do it
in c++ getch() do this.
i want a function like that.
Pausing Execution with Sleep, although I doubt that is the mechanism that you'll want to use. So, as others have suggested, I believe you'll need to implement wait-notify logic. Here's an extremely contrived example:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
#SuppressWarnings("serial")
public class PanelWithButton extends JPanel
{
// Field members
private AtomicBoolean paused;
private JTextArea textArea;
private JButton button;
private Thread threadObject;
/**
* Constructor
*/
public PanelWithButton()
{
paused = new AtomicBoolean(false);
textArea = new JTextArea(5, 30);
button = new JButton();
initComponents();
}
/**
* Initializes components
*/
public void initComponents()
{
// Construct components
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
add( new JScrollPane(textArea));
button.setPreferredSize(new Dimension(100, 100));
button.setText("Pause");
button.addActionListener(new ButtonListener());
add(button);
// Runnable that continually writes to text area
Runnable runnable = new Runnable()
{
#Override
public void run()
{
while(true)
{
for(int i = 0; i < Integer.MAX_VALUE; i++)
{
if(paused.get())
{
synchronized(threadObject)
{
// Pause
try
{
threadObject.wait();
}
catch (InterruptedException e)
{
}
}
}
// Write to text area
textArea.append(Integer.toString(i) + ", ");
// Sleep
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
}
}
}
}
};
threadObject = new Thread(runnable);
threadObject.start();
}
#Override
public Dimension getPreferredSize()
{
return new Dimension(400, 200);
}
/**
* Button action listener
* #author meherts
*
*/
class ButtonListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent evt)
{
if(!paused.get())
{
button.setText("Start");
paused.set(true);
}
else
{
button.setText("Pause");
paused.set(false);
// Resume
synchronized(threadObject)
{
threadObject.notify();
}
}
}
}
}
And here's your main class:
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class MainClass
{
/**
* Main method of this application
*/
public static void main(final String[] arg)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PanelWithButton());
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
});
}
}
As you can see, this example application will continually write to the text area until you click the button that reads 'Pause', whereupon to resume you'll need to click that same button which will now read 'Start'.
You don't say what you mean by pause. What is your app doing?
As a rule of thumb you CAN'T pause a UI app. User interface applications run from a message processing loop. Message comes in, message is dispatched, loop waits for another message. An app still needs to handles things like the user clicking on buttons, resizing the window, closing the app and so forth so this loop runs continuously.
If you want your application to "pause" in the sense of prevent the user doing something, just grey out whatever button or menu it is you don't want users to be doing.
If your app is running a thread in the background and wish it to suspend that action until you resume it, you can do so fairly easily like this.
MyThread mythread = new MyThread();
// Main thread
void pause() {
mythread.pause = true;
}
void resume() {
synchronized (mythread) {
mythread.pause = false;
mythread.notify();
}
}
class MyThread extends Thread {
public boolean pause = false;
public void run() {
while (someCondition) {
synchronized (this) {
if (pause) {
wait();
}
}
doSomething();
}
}
}
It is also possible to use Thread.suspend(), Thread.resume() to accomplish similar but these are inherently dangerous because you have no idea where the thread is when you suspend it. It could have a file open, be half way through sending a message over a socket etc. Putting a test in whatever loop controls your thread allows you do suspend at a point when it is safe to do so.
This answer entirely depends on whether I understand your question correctly, please give a bit more info if you want better answers. Here goes:
Pausing in a loop scenario
boolean paused;
while(true ) {
if(paused)
{
Thread.sleep(1000); // or do whatever you want in the paused state
} else {
doTask1
doTask2
doTask3
}
}
Threads:
You can also put those tasks into a seperate thread and not on the GUI thread which is typically what you would do for long running operations.
Pausing a thread is very easy. Just call suspend() on it. When you want to unpause call resume(). These methods however are dangerous and have been deprecated. Better or rather safer way to do it would be similar to the above by checking a pause flag.Here is a short example I had lying around in my snippets. Cant exactly remember where I got it in the first place:
// Create and start the thread
MyThread thread = new MyThread();
thread.start();
while (true) {
// Do work
// Pause the thread
synchronized (thread) {
thread.pleaseWait = true;
}
// Do work
// Resume the thread
synchronized (thread) {
thread.pleaseWait = false;
thread.notify();
}
// Do work
}
class MyThread extends Thread {
boolean pleaseWait = false;
// This method is called when the thread runs
public void run() {
while (true) {
// Do work
// Check if should wait
synchronized (this) {
while (pleaseWait) {
try {
wait();
} catch (Exception e) {
}
}
}
// Do work
}
}
} // Create and start the thread
MyThread thread = new MyThread();
thread.start();
while (true) {
// Do work
// Pause the thread
synchronized (thread) {
thread.pleaseWait = true;
}
// Do work
// Resume the thread
synchronized (thread) {
thread.pleaseWait = false;
thread.notify();
}
// Do work
}
class MyThread extends Thread {
boolean pleaseWait = false;
// This method is called when the thread runs
public void run() {
while (true) {
// Do work
// Check if should wait
synchronized (this) {
while (pleaseWait) {
try {
wait();
} catch (Exception e) {
}
}
}
// Do work
}
}
}
Hope this helps
try my java pause button:
package drawFramePackage;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.Timer;
public class Milliseconds2 implements ActionListener, MouseListener{
JFrame j;
Timer t;
Integer onesAndZeros, time, time2, placeHolder2;
Boolean hasFired;
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
new Milliseconds2();
}
public Milliseconds2(){
j = new JFrame();
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
j.setSize(new Dimension(300, 300));
j.setVisible(true);
j.addMouseListener(this);
onesAndZeros = new Integer(0);
time = new Integer(0);
time2 = new Integer(0);
placeHolder2 = new Integer(0);
hasFired = new Boolean(true);
t = new Timer(2400, this);
time = (int) System.currentTimeMillis();
t.start();
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
if (onesAndZeros.equals(0)){
t.stop();
if (hasFired){
time2 = t.getDelay() - ((int) System.currentTimeMillis() - time);
}
else{
time2 -= (int) System.currentTimeMillis() - placeHolder2;
}
if (hasFired){
hasFired = false;
}
onesAndZeros = -1;
}
if (onesAndZeros.equals(1)){
//System.out.println(time2);
t.setInitialDelay(time2);
t.start();
placeHolder2 = (int) System.currentTimeMillis();
onesAndZeros = 0;
}
if (onesAndZeros.equals(-1)){
onesAndZeros = 1;
}
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
time = (int) System.currentTimeMillis();
hasFired = true;
System.out.println("Message");
}
}
Freezing your Main Thread will effectively freeze the entire program and could cause the operating system to think the application has crashed, not quite sure so correct me if I'm wrong. You could try to hide/disable the controls and enable them again when the user clicks on your button.
UI performs task using message driven mechanism.
If you have a button in your UI and you want to run something when that button is pressed, you should add an object of ActionListener to your button. Once the button is pressed, it fires the ActionListener object to perform a task, e.g.:
button.addActionListener(new ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// do something
}
});
If you want to stop something when you press a pause button, you will defnitely need a Thread. This is more complicated than the former case.

Categories