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.
Related
I am trying to control a while loop in my program to stop and start based on a user input. I have attempted this with a button and the "start" part of it works but then the code goes into an infinite loop which I cant stop without manually terminating it. The following is all my code:
Header Class
package test;
import javax.swing.JFrame;
public class headerClass {
public static void main (String[] args){
frameClass frame = new frameClass();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(150,75);
frame.setVisible(true);
}
}
Frame Class
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class frameClass extends JFrame {
private JButton click;
public frameClass(){
setLayout(new FlowLayout());
click = new JButton("Stop Loop");
add(click);
thehandler handler = new thehandler();
click.addActionListener(handler);
}
private class thehandler implements ActionListener{
public void actionPerformed(ActionEvent e){
if(e.getSource()==click){
looper loop = new looper();
looper.buttonSet = !looper.buttonSet;
}
}
}
}
Looping class
package test;
public class looper {
public static boolean buttonSet;
public looper(){
while (buttonSet==false){
System.out.println("aaa");
}
}
}
How do I fix this and stop if from going into the infinite loop please?
Swing is a single threaded framework, this means that while the loop is running, the Event Dispatching Thread is been blocked and can't process new events, including repaint requests...
You need to start your Looper class inside it's own thread context. This would also mean that your loop flag would need to be declared volatile or you should use an AtomicBoolean so that state can be inspected and modified across thread boundaries
For example...
public class Looper implements Runnable {
private AtomicBoolean keepRunning;
public Looper() {
keepRunning = new AtomicBoolean(true);
}
public void stop() {
keepRunning.set(false);
}
#Override
public void run() {
while (keepRunning.get()) {
System.out.println("aaa");
}
}
}
Then you might be able to use something like...
private class thehandler implements ActionListener {
private Looper looper;
public void actionPerformed(ActionEvent e) {
if (e.getSource() == click) {
if (looper == null) {
looper = new Looper();
Thread t = new Thread(looper);
t.start();
} else {
looper.stop();
looper = null;
}
}
}
}
to run it...
Take a look at Concurrency in Swing and Concurrency in Java for some more details
Also beware, Swing is not thread safe, you should never create or modify the UI from out side the context of the EDT
The problem is you start an infinite loop and try to terminate it in the same thread. That doesn't work because the VM executes one task in a thread after another. It would execute the command to stop the looper directly after the loop is finished but an infinite loop never finishes. So it cannot be stopped like this.
You need to create a second Thread for the looper. This way you can stop it from your main thread.
I would like to disable a JButton for about 10 seconds. Is there way to do this?
Thank you
Use a Swing Timer, when triggered, it notifies the registered listener within the context of the Event Dispatching Thread, making it safe to update the UI from.
See How to use Swing Timers and Concurrency in Swing for more details
First read the answer from #MadProgrammer and go through the links provided there. If you still need a working example based on those suggestions, following is one.
why the solution is better than few solutions presented
It's because it uses a javax.swing.Timer to enable the button that enables GUI related tasks to be automatically executed on the event-dispatch thread (EDT). This saves the swing application from being intermixed with non EDT operations.
Please try the following example:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SwingDemo extends JPanel {
private final JButton button;
private final Timer stopwatch;
private final int SEC = 10;
public SwingDemo() {
button = new JButton("Click me to disable for " + SEC + " secs");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton toDisable = (JButton) e.getSource();
toDisable.setEnabled(false);
stopwatch.start();
}
});
add(button);
stopwatch = new Timer(SEC * 1000, new MyTimerListener(button));
stopwatch.setRepeats(false);
}
static class MyTimerListener implements ActionListener {
JComponent target;
public MyTimerListener(JComponent target) {
this.target = target;
}
#Override
public void actionPerformed(ActionEvent e) {
target.setEnabled(true);
}
}
public static void main(String[] args) {
final JFrame myApp = new JFrame();
myApp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myApp.setContentPane(new SwingDemo());
myApp.pack();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
myApp.setVisible(true);
}
});
}
}
You can use Thread, Task or the simpler Timer class.
you can use Thread.sleep(time in mil seconds)
ex:
Thread.sleep(10000); // sleep for 10 seconds
JButton button = new JButton("Test");
try {
button.setEnabled(false);
Thread.sleep(10000);
button.setEnabled(true);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
but it must be in a separate thread or it will make all the GUI hang for 10 seconds.
you can post more details about the code and i can help
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();
Why won't this work?
I would like it to print every second.
Thanks.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class test2 {
public static void main(String[] args) {
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("hello");
}
});
timer.start();
}
}
Your program terminates before the timer can run even once. When the main method is terminated the program terminates and all threads will also terminate. This includes your timer thread.
Try the following:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class test2 {
public static void main(String[] args) {
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("hello");
}
});
timer.start();
}
while (true) /* no operation */;
}
}
Probably the timer is started in a daemon thread, and immediately after starting it, the main thread finishes.
As soon as there are only daemon threads left, the JVM may/must terminate. So you need to keep the main thread alive. For testing purposes a simple Thread.sleep(10000); should do well.
There's nothing preventing your code from exiting immediately after the call to start. Add Thread.sleep(10000); after timer.start(); and you'll see the message printed.
Because your program will exit soon after main thread is finished, and since timer runs on a separate thread it won't have time to execute. Adding a Thead.Sleep call before main method end would execute your code.
You are using interface libraries (java.awt) to write console applications.
Try this:
public static void main(String[] args) throws Exception {
while(true){
Thread.sleep(1000);
System.out.println("hello");
}
}
In my java swing application am having a Jframe and Jlabel for displaying current time.
here am using a thread for displaying time in jlablel which is added to the frame.my doubt is that when i dispose the jframe what will happen to the thread whether its running or stopped.
If you have NOT marked your thread as daemon by calling yourThread.setDaemon(true), it will keep running even if main thread in your application has finished. Remember you have to call setDaemon before starting the thread.
Refer my answer to some previous question for details.
The correct way in your case, I believe, would be you maintain a 'stop' flag which is watched by your timer thread. Timer thread should exit on reading this flag as 'false'. You can add a WindowListener to your jframe and on the window closed event set the 'stop' flag to true
Heres example code for what I am suggesting :
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
public class JFrameTest {
public static void main(String[] args) {
final Timer t = new Timer();
t.start();
JFrame jf = new JFrame("GOPI");
jf.setVisible(true);
jf.setSize(100, 100);
jf.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
t.stopTimer();
}
});
System.out.println("JFrameTest.main() DONE");
}
}
class Timer extends Thread {
boolean stop = false;
#Override
public void run() {
for (int i = 0; i < 50; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (stop)
break;
System.out.println("Counting :" + i);
}
System.out.println("Timer exit");
}
public void stopTimer() {
stop = true;
}
}
Your thread will keep running.
You need to either do as suggested by Gopi or you could use System.exit(0) in close operation of your JFrame.
NOTE: I am assuming here that Your application needs to end if this Frame is closed.