I need to wait a few seconds between invoking two different methods in a program with Swing interface. Those methods are not related to the GUI.
firstMethod();
//The interface is changed by other methods
...
//I want to Wait five seconds
secondMethod();
I have tried using a Swing Timer but it does not work. Apparently, the Timer starts but is a non-blocking action, so secondMethod() is executed immediately. I can use sleep(), but that freezes the GUI for those five seconds, so the interface is not updated until after that, which I would prefer to avoid.
I have found here some recommendations to use Future<V> and I have read the Javadoc but I have never used ExecutorService before and I am afraid I may write a too complex piece of code for something that simple.
Any idea on how to do it?
Sounds like your code is something like:
firstMethod();
startTimer();
secondMethod();
I have tried using a Timer but it does not work
You can't just start a Timer and do nothing. When the timer fires you need to invoke the secondMethod(...) in the actionPerformed of the Timer.
Use Swing Timer instead of Java Timer and Thread.sleep.
Please have a look at How to Use Swing Timers
Timer timer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
secondMethod();
}
});
timer.setRepeats(false);
timer.start()
A timer won't just stop code execution like sleep does.
You have to assign an ActionListener to it which will be notified when the time is up.
It goes something like this:
firstMethod();
Timer t = new Timer(5000);
t.setRepeats(false);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
secondMethod();
}
})
t.start();
Related
In the code below I am running my method which adds text to a JTextArea, then i wait 4 seconds and add more text. However it simply waits four seconds then puts all the text down at once. How can I make it so it adds the first text, waits then adds the second block of text?
public static void configuresettings() {
GUI.add("To Begin, Go to www.opionsxo.com");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
GUI.add("Welcome to Configure Settings!");
}
I figured it out, if anyone is interested in how. Then view the code below...
public static void configuresettings() {
GUI.add("To Begin, Go to www.opionsxo.com");
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
GUI.add("Welcome to Configure Settings!");
}
};
Timer timer = new Timer( 4000, actionListener );
timer.setRepeats(false);
timer.start();
}
You shouldn't use Thread.sleep with swing, or it will block your application. For instance, if you resize your window or move a window in front of your application, it won't repaint as needed, because you stopped it. Instead, you should be using Swing Timers.
Your problem is probably because you should revalidate() your JTextArea before sleep or something, but as said, you should change the implementation of it.
Read more here: http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
Don't do anything within the context of the Event Dispatching Thread that might cause it to stop, like calling Thread.sleep.
Instead, trying using a javax.swing.Timer or SwingWorker
Take a look at:
Concurrency in Swing
Worker Threads and SwingWorker
How to Use Swing Timers
For more details
For example:
java for-loop in GUI TextArea
Displaying contents of String array in Swing component as iterations using Time delay. JAVA
I cant run JTextArea multiple times?
Basically, I have this game where once guesses the correct answer it starts a new game with a new word. I want to display Correct! but after three seconds, change it to a empty string. How do I do that?
My attempt:
if (anagram.isCorrect(userInput.getText()))
{
anagram = new Anagram();
answer.setText("CORRECT!");
word.setText(anagram.getRandomScrambledWord());
this.repaint();
try
{
Thread.currentThread().sleep(3000);
}
catch (Exception e)
{
}
answer.setText("");
} else
{
answer.setForeground(Color.pink);
answer.setText("INCORRECT!");
}
Edit:
My solution:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
// TODO add your handling code here:
if (anagram.isCorrect(userInput.getText()))
{
answer.setText("CORRECT!");
ActionListener taskPerformer = new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
anagram = new Anagram();
word.setText(anagram.getRandomScrambledWord());
answer.setText("");
userInput.setText("");
}
};
Timer timer = new Timer(3000, taskPerformer);
timer.setRepeats(false);
timer.start();
} else
{
answer.setForeground(Color.pink);
answer.setText("INCORRECT!");
}
}
I am not sure, but I hope that I am following MadProgrammer's advice and not blocking the event itself, but the new thread. I will look up Java Timer also.
Swing is an event driven environment. While you block the Event Dispatching Thread, no new events can be processed.
You should never block the EDT with any time consuming process (such as I/O, loops or Thread#sleep for example).
You might like to have a read through The Event Dispatch Thread for more information.
Instead, you should use a javax.swing.Timer. It will trigger a ActionListener after a given delay.
The benefit of which is that the actionPerformed method is executed with the context of the Event Dispatching Thread.
Check out this or this or this or this for an examples
it works after 3 seconds..
ActionListener taskPerformer = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
statusbar.setText("Status");
}
};
Timer timer = new Timer(3000, taskPerformer);
timer.setRepeats(false);
timer.start();
if these piece of code is in the event handlers, then you are holding up the UI thread, and it is not going to work as UI update will only happens after you finished your work in the event handlers.
You should create another thread do the work of "sleep 3 second, and change the text field, and trigger repaint". Using Timer or similar utilities is the easiest way to achieve what I am describing.
Sorry for posting yet another thread about Java swing and loops. I have read through others and none of the solutions have really been appropriate for me. Okay so now onto the problem. I have a class extending JFrame in which I have a Timer running a stopwatch as below:
class StopWatch extends TimerTask{
public void run() {
time.setText(String.format("%02d:%02d", minutes_elapsed,seconds_elapsed));
seconds_elapsed++;
if(seconds_elapsed == 60){
seconds_elapsed = 0;
minutes_elapsed++;
}
}
}
Now the only way my Label "time" updates is when I call time.update(time.getGraphics()) but this paints over the previous time. Any ideas what I should do? I have also tried repaint,validate,and paint. Paint does the same thing for me that update does...Any Ideas?
P.S I don't know if it matters or not but I create the Timer in a public void start_timer() function which is like below:
public void start_timer(int minutes, int seconds){
if(timer == null)
timer = new Timer();
timer.scheduleAtFixedRate(new StopWatch(),0,1000);
}
I suspect you're using a java.util.Timer instead of a javax.swing.Timer. The latter will make sure that the timer runs on the UI thread, which I suspect is the problem.
See "How to use Swing Timers" for a tutorial on them. You'll want to convert your TimerTask into an ActionListener`, and then use
timer.setDelay(1000);
timer.setRepeats(true);
timer.start();
You can do this
public void run()
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
// do stuff
}
}
));
}
but you really should be using the javax.swing.Timer though. Remember that Swing is single-threaded and as such, its components must be modified in its thread (i.e. Event Dispatch Thread).
I am making a game having squares in it (a grid of panels) and when the game ends there is an algorithm that changes the color of the panels one by one in a "live" fashion where the user watches the squares change color slowly. I try something like:
Thread.sleep(1000);
grid.getComponent(boxNumber).setBackground(Color.YELLOW);
Thread.sleep(1000);
grid.getComponent(boxNumber).setBackground(Color.ORANGE);
Although the color of a box changes to Yellow, it does not change to Orange afterwards. Anyone have any ideas? Hope I was able to be clear.
Read the section from the Swing tutorial on Concurrency to understand why you should not be using the sleep() method.
One solution is to use a SwingWorker, then you can 'publish' the color of the component so it can be updated properly on the EDT and you can invoke the sleep() method in the worker as well.
These need to happen on the Swing event thread. call set background via:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
grid.getComponent(boxNumber).setBackground(Color.ORANGE);
}
});
Note, your Thread.sleep() should not be in the event thread (or directly from within a Swing event listener (ActionListener, WindowListener, etc).
It would also be prudent to look the Swing Timing Framework which is specifically for things like this.
-Generally its not a good idea to do Thread.sleep(1000); in the EDT. You should try using Timers.
-You also need to call revalidate()/validate() and repaint() afterward.
So maybe something like this:
Timer yellowTimer = new Timer(1000,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jtp.setBackground(Color.YELLOW);
//call revalidate()/validate() and repaint() afterward
jtp.revalidate();
jtp.repaint();
}
});
yellowTimer.setRepeats(false);
Timer orangeTimer = new Timer(2000,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jtp.setBackground(Color.ORANGE);
//call revalidate()/validate() and repaint() afterward
jtp.revalidate();
jtp.repaint();
}
});
orangeTimer.setRepeats(false);
yellowTimer.start();
orangeTimer.start();
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
logger.finest("Reading SMTP Info.");
}
};
Timer timer = new Timer(100 ,taskPerformer);
timer.setRepeats(false);
timer.start();
According to the documentation this timer should fire once but it never fires.
I need it to fire once.
This simple program works for me:
import java.awt.event.*;
import javax.swing.*;
public class Test {
public static void main(String [] args) throws Exception{
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
System.out.println("Reading SMTP Info.");
}
};
Timer timer = new Timer(100 ,taskPerformer);
timer.setRepeats(false);
timer.start();
Thread.sleep(5000);
}
}
This Program will work fine...
setRepeats(boolean flag) function used to set call the function(actionPerformed) repeatedly or only one time if
timer.setRepeats(false) == timer calls the actionperformed method for only one time
timer.setRepeats(true) == timer calls the actionPerformed method repeatedly based on specified time
Swing Timer Work
do the task one time
do the task repeated time
steps to create swing timer:
create the actionlistener
create the timer constructor then pass time and actionlistener in that
implement the actionPerformed() function in which do your task
use timer.start() for start the task between the time specified in timer constructor, use timer.stop() for stop the task
Example:
ActionListener al=new ActionListener() {
public void actionPerformed(ActionEvent ae) {
//do your task
if(work done)
timer.stop();//stop the task after do the work
}
};
Timer timer=new Timer(1000,al);//create the timer which calls the actionperformed method for every 1000 millisecond(1 second=1000 millisecond)
timer.start();//start the task
Your task likely only needs to report results on the event thread (EDT) but do the actual work in a background thread at some periodic rate.
ScheduledExecutorService is EXACTLY what you want. Just remember to update the state of your UI on the EDT via SwingUtility.invokeLater(...)
I'm guessing from the log statement that you're doing some sort of SMTP operation. I think I'm right in saying the java.swing.Timer is intended for UI related timed operations, hence why it needs and EDT running. For more general operations you should use java.util.Timer.
This article is linked from the JavaDocs - http://java.sun.com/products/jfc/tsc/articles/timer/