How to create a delay in Swing

15,859

Solution 1

Well, the following code shows a JFrame with a JTextArea and a JButton. When the buttons is clicked, the Timer send the event repeatedly (with a second delay between them) to the actionListener related to the button which appends a line with the current time.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;


public class TimerTest extends JFrame implements ActionListener{

    private static final long serialVersionUID = 7416567620110237028L;
    JTextArea area;
    Timer timer;
    int count; // Counts the number of sendings done by the timer
    boolean running; // Indicates if the timer is started (true) or stopped (false)

    public TimerTest() {
        super("Test");
        setBounds(30,30,500,500);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(null);

        area = new JTextArea();
        area.setBounds(0, 0, 500, 400);
        add(area);

        JButton button = new JButton("Click Me!");
        button.addActionListener(this);
        button.setBounds(200, 400, 100, 40);
        add(button);

        // Initialization of the timer. 1 second delay and this class as ActionListener
        timer = new Timer(1000, this);
        timer.setRepeats(true); // Send events until someone stops it
        count = 0; // in the beginning, 0 events sended by timer
        running = false;
        System.out.println(timer.isRepeats());
        setVisible(true); // Shows the frame
    }

    public void actionPerformed(ActionEvent e) {
        if (! running) {
            timer.start();
            running = true;
        }
        // Writing the current time and increasing the cont times
        area.append(Calendar.getInstance().getTime().toString()+"\n");
        count++;
        if (count == 10) {
            timer.stop();
            count = 0;
            running = false;
        }
    }

    public static void main(String[] args) {
        // Executing the frame with its Timer
        new TimerTest();
    }
}

Well, this code is a sample of how to use javax.swig.Timer objects. In relation with the particular case of the question. The if statement to stop the timer must change, and, obviously, the actions of the actionPerformed. The following fragment is a skeleton of the solution actionPerformed:

public void actionPerformed(ActionEvent e) {
    if (e.getComponent() == myDealerComponent()) {
    // I do this if statement because the actionPerformed can treat more components
        if (! running) {
            timer.start();
            runnig = true;
        }
        // Hit a card if it must be hitted
        switch (getJBTable(JB.total, JB.aces > 0)) {
          case 0:
              JB.hit();
              break;
          case 1:
              break done;
          case 2:
              JB.hit();
              JB.bet *= 2;
              break done;
        }
        if (JB.total >= 21) { // In this case we don't need count the number of times, only check the JB.total 21 reached
            timer.stop()
            running = false;
        }

    }
}

IMHO this resolves the problem, now @user920769 must think where put the actionListener and the starting/stopping conditions...

@kleopatra: Thanks for show me the existence of this timer class, I don't know nothing about it and it's amazing, make possible a lot of tasked things into a swing application :)

Solution 2

so I looked at Timers, but I could not understand how I could use one for this

The Timer is the solution, since as you say you are updating the GUI which should be done on the EDT.

I'm not sure what your concern is. You deal a card and start the Timer. When the Timer fires you decide to take another card or hold. When you hold your stop the Timer.

Solution 3

Well, a quick explanation about Timers.

First of all, you need a java.util.Timer variable in your class and another class in your project which extends from java.util.TimerTask (let's call it Tasker).

The initialization of the Timer variable is so easy:

Timer timer = new Timer();

Now the Tasker class:

public class Tasker extends TimerTask {
    @Override
    public void run() {
        actionToDo(); // For example take cards 
    }

    // More functions if they are needed
}

Finally, the installation of the timer with its related Tasker:

long delay = 0L;
long period = pauseTime;
timer.schedule(new Tasker(),delay,period);

The schedule function indicates the following: Fisrt param: Action to do each period milliseconds (Executes the run function of a TimerTask class or its extension) Second param: When the timer must start. In this case, it starts when the schedule function is called. The following example indicates a starting 1 second after call the schedule function: timer.schedule(new Tasker(),1000,period); Third param: milliseconds between one call of Tasker.run() function and the following call.

I hope you understand this microtutorial :). If you have any problem, ask for more detailed information!

Kind regards!

Solution 4

I think that in this tutorial is clear how to use Timers in order to achieve what you want, without having to deal with Threads.

Share:
15,859
Fractaly
Author by

Fractaly

I've been programming in Java for about two years, and I have become rather obsessed with it. I have made programs such as a Blackjack Game and a Fractal Viewer, and I find Stack Overflow to be a very valuable resource.

Updated on June 05, 2022

Comments

  • Fractaly
    Fractaly almost 2 years

    I made a blackjack game, and I want the AI player to pause between taking cards. I tried simply using Thread.sleep(x), but that makes it freeze until the AI player is done taking all of his cards. I know that Swing is not thread safe, so I looked at Timers, but I could not understand how I could use one for this. Here is my current code:

    while (JB.total < 21) {
    
              try {
                Thread.sleep(1000);
              } catch (InterruptedException ex) {
                System.out.println("Oh noes!");
              }
    
              switch (getJBTable(JB.total, JB.aces > 0)) {
                case 0:
                  JB.hit();
                  break;
                case 1:
                  break done;
                case 2:
                  JB.hit();
                  JB.bet *= 2;
                  break done;
              }
            }
    

    BTW, the hit(); method updates the GUI.

  • Fractaly
    Fractaly over 12 years
    thanks, but I could you just give me some example code for how to use a timer for this? I tried before, and it threw an error, I forget what is was exactly.
  • kleopatra
    kleopatra over 12 years
    @user920769 to see (and carefully read ;) the error again, try again
  • kleopatra
    kleopatra over 12 years
    (edited to remove the absolutism :-) actually - you rarely use a util.Timer in Swing, instead use swingx.Timer or (for more complex background tasks) SwingWorker
  • Andrew Thompson
    Andrew Thompson over 12 years
    @kleopatra swingx.Timer (scratches head) DYM a javax.swing.Timer? Can't say I've encountered the other one.
  • Charliemops
    Charliemops over 12 years
    Well, I put the code with the util.Timer because is which I used in a project one year ago. My project was a voleyball game and we use the above structure to recalculate information and refresh the window every 0,04 seconds. I don't know how to use swingx.Timer, but this code works correctly in graphical applications. It doesn't freeze the window and let the user do things without any problem. =)
  • kleopatra
    kleopatra over 12 years
    sorry for the confusion, my fault (guilty of subconcious narrow-mindedness ;-) - @Andrew guessed right, I meant javax.swing.Timer and java.util.Timer
  • Charliemops
    Charliemops over 12 years
    Well, I have been reading the swing.Timer API and I have done a code with a Timer which could help @user920769. Due to the extension of the answer, I put it in one new answer. I don't edit this one because, although it isn't the best way, the util.Timer does the trick easily.
  • Fractaly
    Fractaly over 12 years
    Thank you so much for the example, but I am getting an error on these lines: timer = new Timer(1000, this); timer.setRepeats(true); Saying it cannot find the suitable constructor or method, respectively. Were they deprecated?
  • Charliemops
    Charliemops over 12 years
    Do you import the Timer class? The methods are not deprecated even in the last release, therefore it seems your mistake. Here the Java7 ApiDoc
  • user3167101
    user3167101 over 9 years
    esta respuesta es de la buena
  • JayC667
    JayC667 over 3 years
    There's multiple things in your code that you should clean up: 1) don't implements ActionListener! Use Lambdas for button.addActionListener( e -> xyButtonClicked()); This way, you can easily separate concerns without having to check where the Action came from. Especially in cases where you want to invoke them manually. 2) prefix your member variables with visibility (private) and finally wherever you can! If possible, initialize them at variable declaration. 3) myDealerComponent() is the worst name you can give a function, as it's missing getand there's probably some obscure magic invo