Java 计时器从特定时间开始倒计时
Java Timer Countdown from certain time
使用 Java 和 Java Swing 作为 GUI。场景是我希望用户以 HH:MM:SS 的格式输入所需时间(在 JTextbox 中),并从该给定时间开始,按秒倒计时,直到达到零。
目前我正在使用计时器和 timer.between 函数。我根据用户输入时间创建了一个 Instant() 并使用了 instant.now()。
正在创建瞬间,但是,倒计时时钟不会从用户输入时间开始倒计时,而是一些我无法弄清楚它们来自哪里的随机数。其他人能看到问题吗?
javax.swing.Timer countDown = new javax.swing.Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Duration countingDown = Duration.between(Instant.now(), userInputCountDown);
autoShutOffTF.setText(String.format("%02d:%02d:%02d",
countingDown.toHours(),
countingDown.toMinutes() % 60,
countingDown.getSeconds() % 60));
}
});
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//Getting user input, parsing String in the form of HH:MM:SS
String countdownInput = autoShutOffTF.getText();
String getHours = countdownInput.substring(0,2);
int hours = Integer.parseInt(getHours);
String getMins = countdownInput.substring(3,5);
int mins = Integer.parseInt(getMins);
String getSecs = countdownInput.substring(6,8);
int seconds = Integer.parseInt(getSecs);
//Creating a date instance, to get the current year, month and date
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
//creating a new calendar with all of the data
Calendar cal = Calendar.getInstance();
cal.set(year, month, day, hours, mins, seconds);
//creating a new instant with the new calendar with all of the data
userInputCountDown = cal.toInstant();
//starting timer
countDown.start();
}
});
不要用Date
或Calendar
,java.time
API更能达到你想要的效果
看着这个...
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
//creating a new calendar with all of the data
Calendar cal = Calendar.getInstance();
cal.set(year, month, day, hours, mins, seconds);
您正在根据 hours/mins/seconds 创建一个新时间,但是,让我担心的是,如果时间小于现在会发生什么情况?这 "might" 就是您遇到的问题。
因此,您可能想要做的一些事情是验证时间是在当前时间之前还是之后,并相应地滚动一天 - 假设您想要使用绝对时间(即创建一个从现在开始倒计时的计时器到下午 6 点)
这个...
Duration countingDown = Duration.between(Instant.now(), userInputCountDown);
我也觉得不对劲,因为 userInputCountDown
应该是在未来
以下示例采用了一种略有不同的方法,因为它创建了一个 "timer",它将根据当前时间(添加小时、分钟和秒)在未来(基于输入)创建一个目标并将其用作倒计时的锚点。
因此,您可能会说,例如,"create a 1 hour" 计时器。
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextField targetHours;
private JTextField targetMins;
private JTextField targetSeconds;
private Instant futureTime;
private Timer timer;
private JLabel countDown;
public TestPane() {
setLayout(new GridBagLayout());
targetHours = new JTextField("00", 2);
targetMins = new JTextField("00", 2);
targetSeconds = new JTextField("00", 2);
JPanel targetPane = new JPanel(new GridBagLayout());
targetPane.add(targetHours);
targetPane.add(new JLabel(":"));
targetPane.add(targetMins);
targetPane.add(new JLabel(":"));
targetPane.add(targetSeconds);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(8, 8, 8, 8);
add(targetPane, gbc);
JButton btn = new JButton("Start");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
futureTime = LocalDateTime.now()
.plusHours(Long.parseLong(targetHours.getText()))
.plusMinutes(Long.parseLong(targetMins.getText()))
.plusSeconds(Long.parseLong(targetSeconds.getText()))
.atZone(ZoneId.systemDefault()).toInstant();
if (timer != null) {
timer.stop();
}
countDown.setText("---");
timer = new Timer(500, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Duration duration = Duration.between(Instant.now(), futureTime);
if (duration.isNegative()) {
timer.stop();
timer = null;
countDown.setText("00:00:00");
} else {
String formatted = String.format("%02d:%02d:%02d", duration.toHours(), duration.toMinutesPart(), duration.toSecondsPart());
countDown.setText(formatted);
}
}
});
timer.start();
}
});
add(btn, gbc);
countDown = new JLabel("---");
add(countDown, gbc);
}
}
}
警告 - 我没有对输入进行验证,因此您必须小心。
相反,如果您想倒计时到特定时间点(即从现在倒计时到下午 6 点),那么您需要改用 LocalDateTime#withHour(Long)#withMinute(Long)#withSecond(Long)
链。但是,请注意,你必须验证时间是在未来还是过去并采取适当的行动,因为如果你想倒计时到下午 6 点,但现在是晚上 7 点......这实际上意味着什么:/?
使用 Java 和 Java Swing 作为 GUI。场景是我希望用户以 HH:MM:SS 的格式输入所需时间(在 JTextbox 中),并从该给定时间开始,按秒倒计时,直到达到零。 目前我正在使用计时器和 timer.between 函数。我根据用户输入时间创建了一个 Instant() 并使用了 instant.now()。 正在创建瞬间,但是,倒计时时钟不会从用户输入时间开始倒计时,而是一些我无法弄清楚它们来自哪里的随机数。其他人能看到问题吗?
javax.swing.Timer countDown = new javax.swing.Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Duration countingDown = Duration.between(Instant.now(), userInputCountDown);
autoShutOffTF.setText(String.format("%02d:%02d:%02d",
countingDown.toHours(),
countingDown.toMinutes() % 60,
countingDown.getSeconds() % 60));
}
});
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//Getting user input, parsing String in the form of HH:MM:SS
String countdownInput = autoShutOffTF.getText();
String getHours = countdownInput.substring(0,2);
int hours = Integer.parseInt(getHours);
String getMins = countdownInput.substring(3,5);
int mins = Integer.parseInt(getMins);
String getSecs = countdownInput.substring(6,8);
int seconds = Integer.parseInt(getSecs);
//Creating a date instance, to get the current year, month and date
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
//creating a new calendar with all of the data
Calendar cal = Calendar.getInstance();
cal.set(year, month, day, hours, mins, seconds);
//creating a new instant with the new calendar with all of the data
userInputCountDown = cal.toInstant();
//starting timer
countDown.start();
}
});
不要用Date
或Calendar
,java.time
API更能达到你想要的效果
看着这个...
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
//creating a new calendar with all of the data
Calendar cal = Calendar.getInstance();
cal.set(year, month, day, hours, mins, seconds);
您正在根据 hours/mins/seconds 创建一个新时间,但是,让我担心的是,如果时间小于现在会发生什么情况?这 "might" 就是您遇到的问题。
因此,您可能想要做的一些事情是验证时间是在当前时间之前还是之后,并相应地滚动一天 - 假设您想要使用绝对时间(即创建一个从现在开始倒计时的计时器到下午 6 点)
这个...
Duration countingDown = Duration.between(Instant.now(), userInputCountDown);
我也觉得不对劲,因为 userInputCountDown
应该是在未来
以下示例采用了一种略有不同的方法,因为它创建了一个 "timer",它将根据当前时间(添加小时、分钟和秒)在未来(基于输入)创建一个目标并将其用作倒计时的锚点。
因此,您可能会说,例如,"create a 1 hour" 计时器。
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextField targetHours;
private JTextField targetMins;
private JTextField targetSeconds;
private Instant futureTime;
private Timer timer;
private JLabel countDown;
public TestPane() {
setLayout(new GridBagLayout());
targetHours = new JTextField("00", 2);
targetMins = new JTextField("00", 2);
targetSeconds = new JTextField("00", 2);
JPanel targetPane = new JPanel(new GridBagLayout());
targetPane.add(targetHours);
targetPane.add(new JLabel(":"));
targetPane.add(targetMins);
targetPane.add(new JLabel(":"));
targetPane.add(targetSeconds);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(8, 8, 8, 8);
add(targetPane, gbc);
JButton btn = new JButton("Start");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
futureTime = LocalDateTime.now()
.plusHours(Long.parseLong(targetHours.getText()))
.plusMinutes(Long.parseLong(targetMins.getText()))
.plusSeconds(Long.parseLong(targetSeconds.getText()))
.atZone(ZoneId.systemDefault()).toInstant();
if (timer != null) {
timer.stop();
}
countDown.setText("---");
timer = new Timer(500, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Duration duration = Duration.between(Instant.now(), futureTime);
if (duration.isNegative()) {
timer.stop();
timer = null;
countDown.setText("00:00:00");
} else {
String formatted = String.format("%02d:%02d:%02d", duration.toHours(), duration.toMinutesPart(), duration.toSecondsPart());
countDown.setText(formatted);
}
}
});
timer.start();
}
});
add(btn, gbc);
countDown = new JLabel("---");
add(countDown, gbc);
}
}
}
警告 - 我没有对输入进行验证,因此您必须小心。
相反,如果您想倒计时到特定时间点(即从现在倒计时到下午 6 点),那么您需要改用 LocalDateTime#withHour(Long)#withMinute(Long)#withSecond(Long)
链。但是,请注意,你必须验证时间是在未来还是过去并采取适当的行动,因为如果你想倒计时到下午 6 点,但现在是晚上 7 点......这实际上意味着什么:/?