I have a JButton that starts a countdown timer when pressed. When I press the button, it begins, and when I press it again (Button will say "Stop"), it stops. However when I press it again to start the time again I get an error saying:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Timer already cancelled.
Here is my code:
final static Timer t = new Timer();
static void startTimer(JButton b) {
t = new Timer(); // Solved: I needed to create a new Timer object.
t.scheduleAtFixedRate(new TimerTask() {
double timeleft = calcShutterSpeed;
#Override
public void run() {
String s = secondsToMinutes(timeleft);
time.setText(s);
timeleft--;
if (timeleft < 0) {
t.cancel();
b.setText("START TIMER");
b.setForeground(Color.BLACK);
}
}
}, 0, 1000);
}
static void stopTimer() {
t.cancel();
}
/**
* Creates the timer if "Start" is pressed.
*
* #param b
*/
static void timer(JButton b) {
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// If start button is pressed, change text to display stop
if (b.getText() == "START TIMER") {
startTimer(b);
b.setText("STOP TIMER");
b.setForeground(Color.RED);
}
// If stop button is pressed, cancel timer and change text to start
else if (b.getText() == "STOP TIMER") {
stopTimer();
b.setText("START TIMER");
b.setForeground(Color.BLACK);
}
}
});
}
Any tips or suggestions that can fix this problem would be much appreciated. Thanks in advance!
EDIT: Really really simple fix for the curious. The fix is in the code.
I think that the "cancel" method on timer still keeps scheduled task with a cancel status.
The call to "purge" method, directly after the cancel should clean the queue and maybe solve this issue.
Related
I'm trying to stop the program for a second using Swing Timer.
Timer timer = new Timer(10000,
new ActionListener(public void actionPerformed(ActionEvent e) {}));
didn't work
public class Card extends JButton implements ActionListener {
int numberClick = 0;
public card() {
addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
numberClick++;
if(numberClick == 2) {
Timer timer = new Timer(10000, );
timer.start();
numberClick = 0;
}
}
}
You seem to lack basic understanding of how the Timer works. Please read How to Use Swing Timers. The concept is fairly simple.
The first argument in the Timer constructor is the delay. Seems you have that part down. The second argument is the ActionListener that listens for the "Timer Events" (actually ActionEvents). An event is fired each delayed time. The callback (actionPerformed) contains what should be performed after that delay (tick). So whatever you want to happen after that second, put it in the actionPerformed of the timer's ActionListener.
Also if you only want it t occur once, you should call timer.setRepeats(false);. Also note, you are using 10000, which is in milliseconds, so it's 10 seconds, not 1. You should change it to 1000
Example Flow
JButton button = new JButton("Press Me");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
Timer timer = new Timer(1000, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Print after one second");
}
});
timer.setRepeats(false);
timer.start();
}
});
Press Button → Wait One Second → Print Statement
I am trying to implement a Thread.sleep(6000) line but it seems to freeze in the applet. When I tried to use Timers, I wasn't sure how to use because I am not very good with event listeners. I am basically trying to call a method fetchUrl() every 6 seconds, after the user clicks the enter button. How can I implement this?
public void init() {
c = getContentPane();
c.setLayout(flow);
c.setBackground(forum);
question.setForeground(Color.white);
question.setFont(tnr);
question2.setForeground(Color.white);
question2.setFont(tnr);
result.setForeground(Color.white);
result.setFont(tnr);
resp.setBorder(BorderFactory.createBevelBorder(0));
timeLength.setBorder(BorderFactory.createBevelBorder(0));
c.add(question);
c.add(resp);
c.add(question2);
c.add(timeLength);
c.add(enter);
c.add(result);
resp.requestFocus();
enter.addActionListener(this);
t = new Timer(DELAY, this);
t.setInitialDelay(DELAY);
}
public void actionPerformed(ActionEvent e) {
final String n1;
int timeMin, timeSec, count = 0, maxCount;
timeMin = Integer.parseInt(timeLength.getText());
timeSec = timeMin * 60;
maxCount = (int)(timeSec/6);
if (e.getSource() == enter) { //user clicks enter
n1 = resp.getText();
while (count < maxCount) {
fetchUrl(n1); //this method called every 6 seconds
t.start();
count++;
}
}
}
First I would start by separating the ActionListener for the Timer and for the JButton.
Second nothing is happening logically with the Timer because you're swallowing it with the button source check.
Third you should understand how the timer works. Basically for every "tick" (in your case six seconds) the actionPerformed of the timer ActionListener is called. So if you want the fetch() method called, then that's what you should be visible/accessible to the in the Timer's actionPerformed.
The button's ActionListener should only handle the starting of the timer I believe. So just separate the listeners. Give each one an anonymous ActionListener and no need to make the class implement ActionListener.
For example
timer = new Timer(DELAY, new ActionListener(){
public void actionPerformed(ActionEvent e) {
// do some stuff every six seconds
fetchURL();
}
});
enter = new JButton(...);
enter.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
If you want some automatic stopping feature for the timer, you could do something like
timer = new Timer(DELAY, new ActionListener(){
public void actionPerformed(ActionEvent e) {
if (someStoppingCondition()) {
timer.stop();
} else {
// do some stuff every six seconds
fetchURL();
}
// do some stuff every six second
}
});
You need to call a method after user clicks on button every 6 seconds, but you have not said how many times you want to call it.
For infinite number of times, try something like the following,
while(true){
new Thread(){
#Override
public void run(){
try{
Thread.sleep(6000);
fetchUrl(n1);
}catch(InterruptedException e){}
}
}.start();
}
If you will use Thread.sleep() in your applet, then your applet will be hanged for 6 seconds and so create a new thread for it.
I have 6 objects in the class GUI which are moving through the code:
Anim anim = new Anim();
Timer timer = new Timer();
timer.scheduleAtFixedRate(anim, 30, 30);
When an object comes to a point I want to stop it. In class Anim I'm doing:
public class Anim extends TimerTask {
#Override
public void run() {
if (t1.x == 300 && t1.y == 300) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
It stops application, and I want have stayed at a concrete object. How to do it?
EDIT:
Ok, now it works well, does not interfere with other objects. But the object is moving on and after 1 second back to the starting position. I wish the whole time he was in the same position when a sleep.
if (Main.auto1.x == 700 && Main.auto1.y == 350) {
timer = new javax.swing.Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
Main.auto1.x = 700;
Main.auto1.y = 350;
}
});
timer.setRepeats(false);
timer.start();
Use Swing Timer instead of Thread.sleep() and Java Timer in a Swing application that sometime hangs the Swing applicaion.
Read more How to Use Swing Timers
Sample code:
private Timer timer;
...
timer = new javax.swing.Timer(3000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
//do what ever you want to do
// call timer.stop() when the condition is matched
}
});
timer.setRepeats(true);
timer.start();
EDIT
Please have a look at my another post How to fix animation lags in Java?
I'm creating a java program that involves a button that gives a bunch of problems. I'm wondering how can I create a delay between the times a user can click a button (to prevent button spamming). Here is what I tried.
public void ButtonActionPerformed(java.awt.event.ActionEvent evt) {
Thread DelayTHREAD = new Delay();
if(DelayTHREAD.isAlive()) {
/*do nothing*/
}
else {
/*some other code*/
DelayTHREAD.start();
}
}
public static class Delay extends Thread /*Prevents user from spamming buttons*/ {
#Override
public void run() {
try {
Thread.sleep(5000); /*sleeps for the desired delay time*/
}catch(InterruptedException e){
}
}
}
OK so here is the problem, it doesn't matter whether or not the delay thread is started or not, the program still goes on and continues to perform the action performed as if the delay thread never even existed.
Someone please tell me how can I create a delay, so that a user cannot spam button in a program? Thanks :)
You might just create a little method that disables the button for a period of time after the user clicks on it, and then enables it afterward, like so:
static void disable(final AbstractButton b, final long ms) {
b.setEnabled(false);
new SwingWorker() {
#Override protected Object doInBackground() throws Exception {
Thread.sleep(ms);
return null;
}
#Override protected void done() {
b.setEnabled(true);
}
}.execute();
}
Then call it from your actionPerformed method like this:
disable(button, 5000);
Just make sure you call it from the EDT.
Use a SwingTimer to inject a delay between the button click and the activation of the associated action....
import javax.swing.Timer;
/*...*/
private Timer attackTimer;
/*...*/
attackTimer = new Timer(5000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Do attack...
}
});
attackTimer.setRepeats(false);
/*...*/
public void ButtonActionPerformed(java.awt.event.ActionEvent evt) {
// Restart the timer each time the button is clicked...
// In fact, I would disable the button here and re-enable it
// in the timer actionPerformed method...
attackTimer.restart();
}
I am making a simple target shooting game.I have a countdownTimer inside the label and an object that blinks in a random position inside the panel. Every time I click on the object,. the object's timer stops which makes that object stop too, but the countdown timer doesn't and that is my problem. I want the countdown timer should stop also.
Could someone help me about this matter?
Here's the code :
private void starting()
{
new Timer(TIMER_PERIOD, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if (count++ < MAX_COUNT)
{
String text = "Time remaining: (" + (MAX_COUNT - count) + ") seconds left";
setCountDownLabelText(text);
Date date = new Date();
setCountDownPanelText(date);
}
else
{
((Timer) e.getSource()).stop();
randomTimer.stop();
JOptionPane.showMessageDialog(null, "Game Over");
System.exit(0);
}
}
}).start();
}
It strikes me that you don't understand the code at all, that you are unaware of the anonymous class created that is extending Timer, which (if you'd seen the documentation) has a function stop() which does what you ask.
You need to store a reference to the Timer.
private javax.swing.Timer timer;
private void starting() {
timer = new Timer(TIMER_PERIOD, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
// do stuff
// stop the timer
timer.stop();
// do other stuff
}
}
}