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.
    }
}