线程睡眠有问题。我编写了简单的闹钟,它将设置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!");
}
}
}
});
答案 0 :(得分:2)
我将放弃我将如何做(以及它应该如何)。 代码中的注释。
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.
}
}
答案 1 :(得分:1)
你真的不希望程序在计时器熄灭之前“等待”,因为程序将无法执行任何其他操作,包括更新你发现的图形界面。
最佳解决方案是创建一个javax.swing.Timer对象,然后设置timer以在需要的时间过去时通知您的系统。有关创建计时器的详细信息,请参阅https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html。
答案 2 :(得分:-1)
部分问题在于您正在呼叫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()
的调用应该使子线程处于休眠状态,而不会影响应用程序的其余部分。
请注意我正在使用箭头符号(->
)作为主题。你不必。相反,你可以简单地创建一个runnable:
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)更清晰。