如何在 Swing 中创建延迟

发布于 2024-12-01 23:42:00 字数 664 浏览 2 评论 0原文

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

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;
          }
        }

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

怎言笑 2024-12-08 23:42:00

所以我查看了计时器,但我不明白如何使用计时器来实现此目的

,因为正如您所说,您正在更新应该在 EDT 上完成的 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.

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.

吃不饱 2024-12-08 23:42:00

那么,下面的代码显示了一个带有 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();
    }
}

好吧,这段代码是如何使用 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;
        }

    }
}

恕我直言,这解决了问题,现在@user920769必须考虑将actionListener和启动/停止条件放在哪里...

@kleopatra:感谢您向我展示这个计时器类的存在,我对它一无所知,这太神奇了,使很多任务成为可能到一个 Swing 应用程序中:)

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 :)

不一样的天空 2024-12-08 23:42:00

好吧,关于计时器的快速解释。

首先,您的类中需要一个 java.util.Timer 变量,并且项目中需要另一个从 java.util.TimerTask 扩展的类(我们称之为 Tasker)。

Timer 变量的初始化非常简单:

Timer timer = new Timer();

现在是 Tasker 类:

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

    // More functions if they are needed
}

最后,安装计时器及其相关的 Tasker:

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

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

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

亲切的问候!

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!

可是我不能没有你 2024-12-08 23:42:00

我认为在本教程中很清楚如何在为了实现你想要的,而不必处理线程。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文