简体   繁体   English

如何在 Swing 中创建延迟

[英]How to create a delay in Swing

I made a blackjack game, and I want the AI player to pause between taking cards.我做了一个二十一点游戏,我希望 AI 玩家在拿牌之间暂停。 I tried simply using Thread.sleep(x), but that makes it freeze until the AI player is done taking all of his cards.我尝试简单地使用 Thread.sleep(x),但这使它冻结,直到 AI 玩家完成他的所有卡片。 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.我知道 Swing 不是线程安全的,所以我查看了 Timers,但我不明白如何为此使用计时器。 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();顺便说一句,hit(); method updates the GUI.方法更新 GUI。

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.计时器是解决方案,因为正如您所说,您正在更新应该在 EDT 上完成的 GUI。

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.当你按住你的停止计时器。

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).首先,您的类中需要一个 java.util.Timer 变量,并且您的项目中需要另一个从 java.util.TimerTask 扩展而来的类(我们称之为 Tasker)。

The initialization of the Timer variable is so easy: Timer 变量的初始化非常简单:

Timer timer = new Timer();

Now the Tasker class:现在 Tasker 类:

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:最后,安装定时器及其相关的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. schedule 函数指示以下内容: Fisrt param:每个周期毫秒执行的操作(执行 TimerTask 类或其扩展的运行函数) Second param:计时器必须何时启动。 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);下面的例子表示在调用 schedule 函数后开始 1 秒: timer.schedule(new Tasker(),1000,period); Third param: milliseconds between one call of Tasker.run() function and the following call.第三个参数:Tasker.run() 函数的一次调用和下一次调用之间的毫秒数。

I hope you understand this microtutorial :).我希望你理解这个微教程:)。 If you have any problem, ask for more detailed information!如果您有任何问题,请询问更详细的信息!

Kind regards!亲切的问候!

Well, the following code shows a JFrame with a JTextArea and a JButton.好吧,下面的代码显示了一个带有 JTextArea 和 JButton 的 JFrame。 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.当按钮被点击时,定时器将事件重复(在它们之间有第二个延迟)发送到与按钮相关的 actionListener,该按钮附加一行当前时间。

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.好吧,这段代码是如何使用 javax.swig.Timer 对象的示例。 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.停止计时器的 if 语句必须改变,而且很明显,actionPerformed 的动作。 The following fragment is a skeleton of the solution actionPerformed:以下片段是解决方案 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...恕我直言,这解决了问题,现在@user920769 必须考虑将 actionListener 和启动/停止条件放在哪里......

@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 :) @kleopatra:感谢您向我展示这个计时器类的存在,我对此一无所知,这太棒了,可以将很多任务处理到一个 Swing 应用程序中 :)

我认为在本教程中很清楚如何使用定时器来实现你想要的,而不必处理线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM