制作一个不会中断整个程序的倒数计时器?
Making a countdown timer that doesn't interrupt the entire program?
所以我正在尝试制作一个反应游戏,你按下开始按钮,一个隐藏的计时器会从 1 到 10 秒之间的随机数倒计时到零。大多数关于 java 计时器的答案建议使用
Thread.sleep(1000);
然而,这会打断整个程序,而我只是想让它倒计时。我应该如何解决这个问题?
按下开始后,程序从一个随机数开始倒计时。蓝色图标(下面的完整代码)会变成红色,然后你应该按下它,它会显示你按下它所花费的时间。
代码是焦点:
public void countDown() throws InterruptedException {
int random = r.nextInt((10000 - 1000) + 1) + 1000;
while(random >= 0){
Thread.sleep(1000);
random -= 1000;
}
if (random <= 0) {
button_1.setIcon(img_react);
repaint();
}
}
使用的图像文件:
完整代码:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
import java.util.*;
public class Interface extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
ImageIcon img_idle = new ImageIcon("img_idle.png");
ImageIcon img_react = new ImageIcon("img_react.png");
JButton button_1 = new JButton(img_idle);
JButton start = new JButton("Start");
Random r = new Random();
public Interface() {
super("Simple Reaction Game");
setSize(180, 350);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
Container contentArea = getContentPane();
contentArea.setBackground(Color.white);
FlowLayout flowManager = new FlowLayout();
contentArea.setLayout(flowManager);
button_1.addActionListener(this);
start.addActionListener(this);
contentArea.add(button_1);
contentArea.add(start);
setContentPane(contentArea);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == start) {
try {
countDown();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
public void countDown() throws InterruptedException {
Thread t = new Thread();
int random = r.nextInt((10000 - 1000) + 1) + 1000;
while(random >= 0){
t.sleep(1000);
random -= 1000;
}
if (random <= 0) {
button_1.setIcon(img_react);
repaint();
}
}
public static void main(String args[]) {
new Interface();
}
}
我建议使用不同的架构。为什么你认为你需要 "count down" 任何东西?!
意思是:你只关心你想在随机的一段时间后"something"做什么;所以这样的事情(使用伪代码)最终可能会更容易:
now = ... get current time
then = now + random value
schedule the Swing timer to sent some Event X "then"
并且只需要一些代码来响应传入的 X 事件。
你不能只使用Thread.sleep()
,它不会像你想的那样起作用。相反,您可以使用 javax.swing.Timer
来完成您想要做的事情。
文档中的一些注释(如果您懒得阅读的话):
- 计时器使用单个共享线程执行它们的等待。
- 计时器可以安全地对Swing 组件执行操作。
- 计时器可以安全地对Swing 组件执行操作。
- javax.swing.Timer 有两个功能可以使其更易于使用 GUI。
我已经修改了 中的一个示例,以展示如何根据您的需要调整它。它使用您随机生成的数字,该数字是在每次计时器结束并您按 "start" 时生成的。
import java.awt.*;
import java.awt.event.*;
import java.text.SimpleDateFormat;
import javax.swing.*;
import javax.swing.UnsupportedLookAndFeelException;
import java.util.Random;
public class Interface {
public static void main(String[] args) {
new Interface();
}
public Interface() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Timer timer;
private long startTime = -1;
private long duration;
private JLabel label;
private JButton start;
public TestPane() {
start = new JButton("Start");
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
timer = new Timer(10, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (startTime < 0) {
startTime = System.currentTimeMillis();
}
long now = System.currentTimeMillis();
long clockTime = now - startTime;
if (clockTime >= duration) {
clockTime = duration;
timer.stop();
}
SimpleDateFormat df = new SimpleDateFormat("mm:ss:SSS");
label.setText(df.format(duration - clockTime));
}
});
timer.setInitialDelay(0);
start.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (!timer.isRunning()) {
duration = new Random().nextInt((10000 - 1000) + 1) + 1000;
startTime = -1;
timer.start();
}
}
});
label = new JLabel("...");
add(label);
add(start);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 250);
}
}
}
所以我正在尝试制作一个反应游戏,你按下开始按钮,一个隐藏的计时器会从 1 到 10 秒之间的随机数倒计时到零。大多数关于 java 计时器的答案建议使用
Thread.sleep(1000);
然而,这会打断整个程序,而我只是想让它倒计时。我应该如何解决这个问题?
按下开始后,程序从一个随机数开始倒计时。蓝色图标(下面的完整代码)会变成红色,然后你应该按下它,它会显示你按下它所花费的时间。
代码是焦点:
public void countDown() throws InterruptedException {
int random = r.nextInt((10000 - 1000) + 1) + 1000;
while(random >= 0){
Thread.sleep(1000);
random -= 1000;
}
if (random <= 0) {
button_1.setIcon(img_react);
repaint();
}
}
使用的图像文件:
完整代码:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
import java.util.*;
public class Interface extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
ImageIcon img_idle = new ImageIcon("img_idle.png");
ImageIcon img_react = new ImageIcon("img_react.png");
JButton button_1 = new JButton(img_idle);
JButton start = new JButton("Start");
Random r = new Random();
public Interface() {
super("Simple Reaction Game");
setSize(180, 350);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
Container contentArea = getContentPane();
contentArea.setBackground(Color.white);
FlowLayout flowManager = new FlowLayout();
contentArea.setLayout(flowManager);
button_1.addActionListener(this);
start.addActionListener(this);
contentArea.add(button_1);
contentArea.add(start);
setContentPane(contentArea);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == start) {
try {
countDown();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
public void countDown() throws InterruptedException {
Thread t = new Thread();
int random = r.nextInt((10000 - 1000) + 1) + 1000;
while(random >= 0){
t.sleep(1000);
random -= 1000;
}
if (random <= 0) {
button_1.setIcon(img_react);
repaint();
}
}
public static void main(String args[]) {
new Interface();
}
}
我建议使用不同的架构。为什么你认为你需要 "count down" 任何东西?!
意思是:你只关心你想在随机的一段时间后"something"做什么;所以这样的事情(使用伪代码)最终可能会更容易:
now = ... get current time
then = now + random value
schedule the Swing timer to sent some Event X "then"
并且只需要一些代码来响应传入的 X 事件。
你不能只使用Thread.sleep()
,它不会像你想的那样起作用。相反,您可以使用 javax.swing.Timer
来完成您想要做的事情。
文档中的一些注释(如果您懒得阅读的话):
- 计时器使用单个共享线程执行它们的等待。
- 计时器可以安全地对Swing 组件执行操作。
- 计时器可以安全地对Swing 组件执行操作。
- javax.swing.Timer 有两个功能可以使其更易于使用 GUI。
我已经修改了
import java.awt.*;
import java.awt.event.*;
import java.text.SimpleDateFormat;
import javax.swing.*;
import javax.swing.UnsupportedLookAndFeelException;
import java.util.Random;
public class Interface {
public static void main(String[] args) {
new Interface();
}
public Interface() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Timer timer;
private long startTime = -1;
private long duration;
private JLabel label;
private JButton start;
public TestPane() {
start = new JButton("Start");
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
timer = new Timer(10, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (startTime < 0) {
startTime = System.currentTimeMillis();
}
long now = System.currentTimeMillis();
long clockTime = now - startTime;
if (clockTime >= duration) {
clockTime = duration;
timer.stop();
}
SimpleDateFormat df = new SimpleDateFormat("mm:ss:SSS");
label.setText(df.format(duration - clockTime));
}
});
timer.setInitialDelay(0);
start.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (!timer.isRunning()) {
duration = new Random().nextInt((10000 - 1000) + 1) + 1000;
startTime = -1;
timer.start();
}
}
});
label = new JLabel("...");
add(label);
add(start);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 250);
}
}
}