如何在 Swing 中创建延迟
Posted
技术标签:
【中文标题】如何在 Swing 中创建延迟【英文标题】:How to create a delay in Swing 【发布时间】:2011-11-07 06:34:55 【问题描述】:我做了一个二十一点游戏,我希望 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;
顺便说一句,hit();方法更新 GUI。
【问题讨论】:
【参考方案1】:好吧,关于计时器的简要说明。
首先,您的类中需要一个 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);
调度功能指示如下:
第一个参数:每个周期毫秒执行的操作(执行 TimerTask 类或其扩展的运行函数)
第二个参数:计时器必须启动的时间。在这种情况下,它在调用 schedule 函数时启动。以下示例表示调用 schedule 函数后 1 秒开始:timer.schedule(new Tasker(),1000,period);
第三个参数:Tasker.run() 函数的一次调用与下一次调用之间的毫秒数。
我希望你理解这个微教程:)。如果您有任何问题,请询问更详细的信息!
亲切的问候!
【讨论】:
(已编辑以消除绝对主义 :-) 实际上 - 您很少在 Swing 中使用 util.Timer,而是使用 swingx.Timer 或(对于更复杂的后台任务)SwingWorker @kleopatraswingx.Timer
(挠头)DYM a javax.swing.Timer
?不能说我遇到过另一个。
好吧,我把代码和 util.Timer 放在一起,因为这是我一年前在一个项目中使用的。我的项目是一场排球比赛,我们使用上述结构重新计算信息并每 0.04 秒刷新一次窗口。我不知道如何使用 swingx.Timer,但这段代码在图形应用程序中可以正常工作。它不会冻结窗口,让用户毫无问题地做事。 =)
对不起,我的错,我的错(潜意识狭隘;-) - @Andrew 猜对了,我的意思是 javax.swing.Timer 和 java.util.Timer
好吧,我一直在阅读 swing.Timer API,并且我已经使用 Timer 编写了一个代码,可以帮助@user920769。由于答案的扩展,我把它放在一个新的答案中。我不编辑这个,因为虽然它不是最好的方法,但 util.Timer 很容易做到这一点。【参考方案2】:
下面的代码显示了一个带有 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:感谢您向我展示了这个计时器类的存在,我对它一无所知,这太棒了,可以将很多有任务的事情变成一个摇摆应用程序:)
【讨论】:
非常感谢您提供的示例,但我在以下几行中遇到错误: timer = new Timer(1000, this); timer.setRepeats(true);分别说它找不到合适的构造函数或方法。它们被弃用了吗? 你是否导入了 Timer 类?即使在最后一个版本中,这些方法也没有被弃用,因此这似乎是你的错误。 Here the Java7 ApiDoc 你的代码中有很多东西需要清理:1) 不要implements ActionListener
!为button.addActionListener( e -> xyButtonClicked());
使用 Lambdas 这样,您可以轻松分离关注点,而无需检查 Action 的来源。特别是在您想手动调用它们的情况下。 2)在您的成员变量前面加上可见性(私有),最后在任何地方都可以!如果可能,在变量声明时初始化它们。 3) myDealerComponent()
是你能给函数起的最糟糕的名字,因为它缺少 get
并且可能有一些不起眼的魔法 invo【参考方案3】:
我认为this tutorial 中明确了如何使用定时器来实现你想要的,而不必处理线程。
【讨论】:
esta respuesta es de la buena【参考方案4】:所以我查看了 Timers,但我不明白如何使用 Timers
计时器是解决方案,因为正如您所说,您正在更新应该在 EDT 上完成的 GUI。
我不确定您的担忧是什么。你发一张牌并启动计时器。当计时器触发时,您决定拿另一张牌或持有。当您按住停止计时器时。
【讨论】:
谢谢,但我能给我一些示例代码来说明如何为此使用计时器吗?我之前试过,它抛出了一个错误,我忘记了到底是什么。 @user920769 再次查看(并仔细阅读;)错误,再试一次以上是关于如何在 Swing 中创建延迟的主要内容,如果未能解决你的问题,请参考以下文章
Java Swing 如何在我的自定义 ColorChooserPanel 中创建颜色样本?