GUI 动作侦听器中的线程休眠 JAVA
Thread sleep in GUI Action Listener JAVA
线程睡眠有问题。我正在编写简易闹钟,它将设置 10 分钟,然后在标签(lab1)中倒计时。当我按下按钮时,它冻结了,仅此而已。问题在哪里?
到目前为止,我不能将线程作为主线程来工作,这就是它是线性的原因。
我可以问一个问题吗?如何执行 shell 命令? (抱歉,它想让这个时间更长。但我也很感兴趣);
public class Budik extends JFrame{
private JLabel lab1,lab2;
private JButton butt1,butt2,butt3;
private JTextField t1,t2;
private JSpinner spinner;
private JCheckBox cx1,cx2;
private JList list;
private JPanel p1,p2,p3,p4,p5;
private JPasswordField pass1,pass2;
public static void main(String[] args)
{
Budik okno = new Budik();
okno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
okno.setVisible(true);
okno.pack();
okno.setLocationRelativeTo(null);
okno.setResizable(false);
}
public Budik() {
super("Countdown");
setLayout(new BorderLayout());
/////////////////////////////////////////////////////////////////
// p1
GridLayout el = new GridLayout(2,1);
p1 = new JPanel(el);
add(p1,BorderLayout.NORTH);
lab1 = new JLabel("Welcome",SwingConstants.CENTER); //centr labelu
lab2 = new JLabel("Created by WajFaj",SwingConstants.CENTER); //centr labelu
lab1.setFont(new Font("Serif", Font.PLAIN, 36)); //velikost fontu
p1.add(lab1);
p1.add(lab2);
//p2
p2 = new JPanel();
add(p2,BorderLayout.WEST);
butt1 = new JButton("START");
p2.add(butt1);
//p3
p3 = new JPanel();
add(p3,BorderLayout.CENTER);
butt2 = new JButton("STOP");
p3.add(butt2);
//p4
p4 = new JPanel();
add(p4,BorderLayout.EAST);
butt3 = new JButton("RESET");
p4.add(butt3);
//p5
p5 = new JPanel();
add(p5,BorderLayout.SOUTH);
butt1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt){
for(int i=600; i>0;i-- ){
try{
Thread.sleep(1000);
String cc = ""+i;
lab1.setText(cc);
}
catch(InterruptedException e){
System.out.println("Chyba!");
}
}
}
});
部分问题是您正在调用 Thread.sleep()
这就是让 Main 线程进入休眠状态,这样整个应用程序就会停止执行。
for(int i=600; i>0;
try{
Thread.sleep(1000);
String cc = ""+i;
lab1.setText(cc);
}
对于您的应用程序,听起来您需要为 运行 创建一个单独的线程,然后将唤醒并实际 运行 闹钟。
也许可以试试这样:
Thread t = new Thread(() -> {
for(int i=600; i>0;i-- ){
try{
Thread.sleep(1000);
String cc = ""+i;
lab1.setText(cc);
}
catch(InterruptedException e){
System.out.println("Chyba!");
}
}
});
t.start();
对 Thread.sleep()
的调用应使子线程进入休眠状态,不会影响应用程序的其余部分。
请注意,我在线程中使用了箭头符号 (->
)。你不必。相反,您可以简单地创建一个 运行nable:
Runnable alarmRunnable = new Runnable() {
@Override
public void run() {
for(int i=600; i>0;i-- ){
try{
Thread.sleep(1000);
String cc = ""+i;
lab1.setText(cc);
}
catch(InterruptedException e){
System.out.println("Chyba!");
}
}
}
};
Thread t = new Thread(alarmRunnable);
t.start();
我认为箭头表示法(也称为 lambda)更简洁。
您真的不希望您的程序 "wait" 直到计时器关闭,因为那时程序将无法执行任何其他操作,包括您发现的更新图形界面。
最好的解决方案是创建一个 javax.swing.Timer 对象,然后设置计时器以在需要的时间过去时通知您的系统。有关创建计时器的详细信息,请参阅 https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html。
我将在这里说明我将如何做(以及它应该如何做)。
代码内注释。
package test;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.TimeUnit;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Budik extends JFrame {
private static final int SLEEP_MINUTES = 10;
private long endTime;
private JLabel lab1, lab2;
private JButton butt1, butt2, butt3;
private JTextField t1, t2;
private JSpinner spinner;
private JCheckBox cx1, cx2;
private JList list;
private JPanel p1, p2, p3, p4, p5;
private JPasswordField pass1, pass2;
private Timer timer;
public static void main(String[] args) {
//All swing applications must run on EDT.
//Take a look https://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(()->{
Budik okno = new Budik();
okno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
okno.pack();
okno.setLocationRelativeTo(null);
okno.setResizable(false);
okno.setVisible(true); //First pack, then setVisible(), recommended.
});
}
public Budik() {
super("Countdown");
setLayout(new BorderLayout());
/////////////////////////////////////////////////////////////////
// p1
GridLayout el = new GridLayout(2, 1);
p1 = new JPanel(el);
add(p1, BorderLayout.NORTH);
lab1 = new JLabel("Welcome", SwingConstants.CENTER); // centr labelu
lab2 = new JLabel("Created by WajFaj", SwingConstants.CENTER); // centr labelu
lab1.setFont(new Font("Serif", Font.PLAIN, 36)); // velikost fontu
p1.add(lab1);
p1.add(lab2);
// p2
p2 = new JPanel();
add(p2, BorderLayout.WEST);
butt1 = new JButton("START");
p2.add(butt1);
// p3
p3 = new JPanel();
add(p3, BorderLayout.CENTER);
butt2 = new JButton("STOP");
p3.add(butt2);
// p4
p4 = new JPanel();
add(p4, BorderLayout.EAST);
butt3 = new JButton("RESET");
p4.add(butt3);
// p5
p5 = new JPanel();
add(p5, BorderLayout.SOUTH);
butt1.addActionListener(e->{
endTime = System.currentTimeMillis()+TimeUnit.MINUTES.toMillis(SLEEP_MINUTES); //define the end time
timer.start(); //Start the timer (in stop button, just add timer.stop())
});
//Initialize timer.
timer = new Timer(1000, e->{ //Loop every 1000ms a.k.a 1second
long millisBeforeEnd = endTime - System.currentTimeMillis();
if (millisBeforeEnd < 0) {
timer.stop();
lab1.setText("Welcome"); //Restore the text to your label, or write whatever you want.
return;
}
long secsBeforeEnd = TimeUnit.MILLISECONDS.toSeconds(millisBeforeEnd); //Convert the millis to seconds.
lab1.setText(secsBeforeEnd+"");
//If you want some kind of pretty print, uncomment the code below.
/*
int hours = (int) TimeUnit.MILLISECONDS.toHours(millisBeforeEnd);
int mins = (int) (TimeUnit.MILLISECONDS.toMinutes(millisBeforeEnd) - hours * 60);
int secs = (int) (TimeUnit.MILLISECONDS.toSeconds(millisBeforeEnd) - mins * 60 - hours * 60 * 60);
lab1.setText(String.format("%02d:%02d:%02d", hours, mins, secs));
*/
});
timer.setInitialDelay(0); //Don't loose the first second.
}
}
线程睡眠有问题。我正在编写简易闹钟,它将设置 10 分钟,然后在标签(lab1)中倒计时。当我按下按钮时,它冻结了,仅此而已。问题在哪里? 到目前为止,我不能将线程作为主线程来工作,这就是它是线性的原因。 我可以问一个问题吗?如何执行 shell 命令? (抱歉,它想让这个时间更长。但我也很感兴趣);
public class Budik extends JFrame{
private JLabel lab1,lab2;
private JButton butt1,butt2,butt3;
private JTextField t1,t2;
private JSpinner spinner;
private JCheckBox cx1,cx2;
private JList list;
private JPanel p1,p2,p3,p4,p5;
private JPasswordField pass1,pass2;
public static void main(String[] args)
{
Budik okno = new Budik();
okno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
okno.setVisible(true);
okno.pack();
okno.setLocationRelativeTo(null);
okno.setResizable(false);
}
public Budik() {
super("Countdown");
setLayout(new BorderLayout());
/////////////////////////////////////////////////////////////////
// p1
GridLayout el = new GridLayout(2,1);
p1 = new JPanel(el);
add(p1,BorderLayout.NORTH);
lab1 = new JLabel("Welcome",SwingConstants.CENTER); //centr labelu
lab2 = new JLabel("Created by WajFaj",SwingConstants.CENTER); //centr labelu
lab1.setFont(new Font("Serif", Font.PLAIN, 36)); //velikost fontu
p1.add(lab1);
p1.add(lab2);
//p2
p2 = new JPanel();
add(p2,BorderLayout.WEST);
butt1 = new JButton("START");
p2.add(butt1);
//p3
p3 = new JPanel();
add(p3,BorderLayout.CENTER);
butt2 = new JButton("STOP");
p3.add(butt2);
//p4
p4 = new JPanel();
add(p4,BorderLayout.EAST);
butt3 = new JButton("RESET");
p4.add(butt3);
//p5
p5 = new JPanel();
add(p5,BorderLayout.SOUTH);
butt1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt){
for(int i=600; i>0;i-- ){
try{
Thread.sleep(1000);
String cc = ""+i;
lab1.setText(cc);
}
catch(InterruptedException e){
System.out.println("Chyba!");
}
}
}
});
部分问题是您正在调用 Thread.sleep()
这就是让 Main 线程进入休眠状态,这样整个应用程序就会停止执行。
for(int i=600; i>0;
try{
Thread.sleep(1000);
String cc = ""+i;
lab1.setText(cc);
}
对于您的应用程序,听起来您需要为 运行 创建一个单独的线程,然后将唤醒并实际 运行 闹钟。
也许可以试试这样:
Thread t = new Thread(() -> {
for(int i=600; i>0;i-- ){
try{
Thread.sleep(1000);
String cc = ""+i;
lab1.setText(cc);
}
catch(InterruptedException e){
System.out.println("Chyba!");
}
}
});
t.start();
对 Thread.sleep()
的调用应使子线程进入休眠状态,不会影响应用程序的其余部分。
请注意,我在线程中使用了箭头符号 (->
)。你不必。相反,您可以简单地创建一个 运行nable:
Runnable alarmRunnable = new Runnable() {
@Override
public void run() {
for(int i=600; i>0;i-- ){
try{
Thread.sleep(1000);
String cc = ""+i;
lab1.setText(cc);
}
catch(InterruptedException e){
System.out.println("Chyba!");
}
}
}
};
Thread t = new Thread(alarmRunnable);
t.start();
我认为箭头表示法(也称为 lambda)更简洁。
您真的不希望您的程序 "wait" 直到计时器关闭,因为那时程序将无法执行任何其他操作,包括您发现的更新图形界面。
最好的解决方案是创建一个 javax.swing.Timer 对象,然后设置计时器以在需要的时间过去时通知您的系统。有关创建计时器的详细信息,请参阅 https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html。
我将在这里说明我将如何做(以及它应该如何做)。 代码内注释。
package test;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.TimeUnit;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Budik extends JFrame {
private static final int SLEEP_MINUTES = 10;
private long endTime;
private JLabel lab1, lab2;
private JButton butt1, butt2, butt3;
private JTextField t1, t2;
private JSpinner spinner;
private JCheckBox cx1, cx2;
private JList list;
private JPanel p1, p2, p3, p4, p5;
private JPasswordField pass1, pass2;
private Timer timer;
public static void main(String[] args) {
//All swing applications must run on EDT.
//Take a look https://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(()->{
Budik okno = new Budik();
okno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
okno.pack();
okno.setLocationRelativeTo(null);
okno.setResizable(false);
okno.setVisible(true); //First pack, then setVisible(), recommended.
});
}
public Budik() {
super("Countdown");
setLayout(new BorderLayout());
/////////////////////////////////////////////////////////////////
// p1
GridLayout el = new GridLayout(2, 1);
p1 = new JPanel(el);
add(p1, BorderLayout.NORTH);
lab1 = new JLabel("Welcome", SwingConstants.CENTER); // centr labelu
lab2 = new JLabel("Created by WajFaj", SwingConstants.CENTER); // centr labelu
lab1.setFont(new Font("Serif", Font.PLAIN, 36)); // velikost fontu
p1.add(lab1);
p1.add(lab2);
// p2
p2 = new JPanel();
add(p2, BorderLayout.WEST);
butt1 = new JButton("START");
p2.add(butt1);
// p3
p3 = new JPanel();
add(p3, BorderLayout.CENTER);
butt2 = new JButton("STOP");
p3.add(butt2);
// p4
p4 = new JPanel();
add(p4, BorderLayout.EAST);
butt3 = new JButton("RESET");
p4.add(butt3);
// p5
p5 = new JPanel();
add(p5, BorderLayout.SOUTH);
butt1.addActionListener(e->{
endTime = System.currentTimeMillis()+TimeUnit.MINUTES.toMillis(SLEEP_MINUTES); //define the end time
timer.start(); //Start the timer (in stop button, just add timer.stop())
});
//Initialize timer.
timer = new Timer(1000, e->{ //Loop every 1000ms a.k.a 1second
long millisBeforeEnd = endTime - System.currentTimeMillis();
if (millisBeforeEnd < 0) {
timer.stop();
lab1.setText("Welcome"); //Restore the text to your label, or write whatever you want.
return;
}
long secsBeforeEnd = TimeUnit.MILLISECONDS.toSeconds(millisBeforeEnd); //Convert the millis to seconds.
lab1.setText(secsBeforeEnd+"");
//If you want some kind of pretty print, uncomment the code below.
/*
int hours = (int) TimeUnit.MILLISECONDS.toHours(millisBeforeEnd);
int mins = (int) (TimeUnit.MILLISECONDS.toMinutes(millisBeforeEnd) - hours * 60);
int secs = (int) (TimeUnit.MILLISECONDS.toSeconds(millisBeforeEnd) - mins * 60 - hours * 60 * 60);
lab1.setText(String.format("%02d:%02d:%02d", hours, mins, secs));
*/
});
timer.setInitialDelay(0); //Don't loose the first second.
}
}