java 如何在 Swing 中创建延迟

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7251625/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 19:17:08  来源:igfitidea点击:

How to create a delay in Swing

javaswingsleepdelaythread-sleep

提问by Fractaly

I made a blackHyman 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:

我做了一个二十一点游戏,我希望 AI 玩家在拿牌之间暂停。我尝试简单地使用 Thread.sleep(x),但这使它冻结,直到 AI 玩家完成他的所有卡片。我知道 Swing 不是线程安全的,所以我查看了 Timers,但我不明白如何为此使用计时器。这是我当前的代码:

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.

顺便说一句,hit(); 方法更新 GUI。

采纳答案by Charliemops

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.

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

好吧,这段代码是如何使用 javax.swig.Timer 对象的示例。关于问题的具体情况。停止计时器的 if 语句必须改变,而且很明显,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 应用程序中 :)

回答by camickr

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.

我不确定你的担忧是什么。你发一张牌并启动计时器。当计时器触发时,您决定拿另一张牌还是保留牌。当你按住你的停止计时器。

回答by Charliemops

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. 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.

schedule 函数指示以下内容: Fisrt param:每个周期毫秒执行的操作(执行 TimerTask 类或其扩展的运行函数) Second param:计时器必须何时启动。在这种情况下,它会在调用调度函数时启动。以下示例表示调用 schedule 函数后开始的 1 秒:timer.schedule(new Tasker(),1000,period);第三个参数:Tasker.run() 函数的一次调用与下一次调用之间的毫秒数。

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

我希望你理解这个微教程:)。如果您有任何问题,请询问更详细的信息!

Kind regards!

亲切的问候!

回答by Luismahou

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

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