GUI动作侦听器JAVA中的线程休眠

时间:2018-05-10 19:26:16

标签: java user-interface label actionlistener thread-sleep

线程睡眠有问题。我编写了简单的闹钟,它将设置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!");
                }
               }
             }
         });

3 个答案:

答案 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)更清晰。