当我尝试用无尽的时间更新JTextField时,为什么我的程序会冻结?

时间:2017-01-11 07:07:37

标签: java swing while-loop

我正在尝试制作计时器,但当我点击“Iniciar(开始)”时,程序会冻结。这是给我带来问题的部分:

ActionListener escucha = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            iniciar.setEnabled(false);
            pausar.setEnabled(true);
            reiniciar.setEnabled(true);
            rb1.setEnabled(false);
            rb2.setEnabled(false);

            try {
                while (true) {
                    milisegundos++;
                    if (milisegundos > 999) {
                        milisegundos = 0;
                        segundos++;
                        if (segundos > 59) {
                            segundos = 0;
                            minutos++;
                            if (minutos > 59) {
                                minutos = 0;
                                horas++;
                            }
                        }
                    }

                    if (milisegundos < 10) {
                        MS = "00"+milisegundos;
                    } else if (milisegundos < 100) {
                        MS = "0"+milisegundos;
                    } else {
                        MS = Integer.toString(milisegundos);
                    }

                    if (segundos < 10) {
                        S = "0"+segundos;
                    } else {
                        S = Integer.toString(segundos);
                    }

                    if (minutos < 10) {
                        M = "0"+minutos;
                    } else {
                        M = Integer.toString(minutos);
                    }

                    if (horas < 10) {
                        H = "0"+horas;
                    } else {
                        H = Integer.toString(horas);
                    }

                    cadena = H+":"+M+":"+":"+S+":"+MS;
                    tiempo.setText(cadena);
                    panel.repaint();

                }   
            } catch (Exception w) {
                w.printStackTrace();
            }
        }
    };

    iniciar.setText("Iniciar");
    iniciar.addActionListener(escucha);

我已经做了另一个类似的算法,但它是一个非常基本的数字时钟,使用相同的方法和一个Thread.sleep()并且它可以工作:

    import java.util.Date;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.Font;

public class asdfasdflkj {

public static void main(String[] args) {
    try {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        JLabel lblHoli = new JLabel("Holi");
        lblHoli.setFont(new Font("Arial", Font.PLAIN, 43));


        frame.setTitle("Hola Gráfica");
        frame.setSize(400, 200);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(panel);

        panel.setLayout(null);
        panel.add(lblHoli);

        lblHoli.setBounds(10, 11, 364, 106);

        int hora, minuto, segundo;

        while (true) {
            Date dt = new Date();
            hora = dt.getHours();
            minuto = dt.getMinutes();
            segundo = dt.getSeconds();

            lblHoli.setText(hora+":"+minuto+":"+segundo);
            Thread.sleep(1000);

        }
    } catch (Exception e) {
        e.printStackTrace();
    }


}
}

少编辑:发布所有程序代码(不完整):

    import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import java.awt.Toolkit;
import javax.swing.SwingConstants;
import java.awt.Font;

公共班主任{

public static int horas = 0, minutos = 0, segundos = 0, milisegundos = 0;
public static String cadena = "00:00:00:00", MS, S, M, H;
public static boolean condición = true, alredySelected = false;

public static void main(String[] args) {

    JFrame frame = new JFrame();
    JPanel panel = new JPanel();
    JPanel panel_botones = new JPanel();
    JPanel panel_opciones = new JPanel();
    JRadioButton rb1 = new JRadioButton();
    JRadioButton rb2 = new JRadioButton();
    ButtonGroup bg = new ButtonGroup();
    JButton iniciar = new JButton();
    JButton pausar = new JButton();
    JButton reiniciar = new JButton();
    Dimension minimumSize = new Dimension(400, 200);
    JTextField tiempo = new JTextField(cadena);
    JCheckBox siempreArriba = new JCheckBox();

    tiempo.setFont(new Font("Arial", Font.BOLD, 45));
    tiempo.setHorizontalAlignment(SwingConstants.CENTER);
    tiempo.setEditable(false);

    pausar.setEnabled(false);
    reiniciar.setEnabled(false);

    frame.setTitle("Cronómetro");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(minimumSize);
    frame.setMinimumSize(minimumSize);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    frame.setIconImage(Toolkit.getDefaultToolkit().getImage(principal.class.getResource("/icons/icono.png")));

    panel.setLayout(new BorderLayout());
    panel.add(panel_botones, BorderLayout.PAGE_END);
    panel.add(panel_opciones, BorderLayout.PAGE_START);
    panel.add(tiempo, BorderLayout.CENTER);
    panel.add(siempreArriba, BorderLayout.EAST);

    panel_botones.setLayout(new FlowLayout());
    panel_botones.add(iniciar);
    panel_botones.add(pausar);
    panel_botones.add(reiniciar);

    siempreArriba.setText("Siempre arriba");
    siempreArriba.addItemListener(new ItemListener(){
        public void itemStateChanged(ItemEvent e) {
            if (siempreArriba.isSelected()) {
                frame.setAlwaysOnTop(true);
            }else{
                frame.setAlwaysOnTop(false);
            }
        }
    });

    ActionListener escucha = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            iniciar.setEnabled(false);
            pausar.setEnabled(true);
            reiniciar.setEnabled(true);
            rb1.setEnabled(false);
            rb2.setEnabled(false);

            try {
                while (true) {
                    milisegundos++;
                    if (milisegundos > 999) {
                        milisegundos = 0;
                        segundos++;
                        if (segundos > 59) {
                            segundos = 0;
                            minutos++;
                            if (minutos > 59) {
                                minutos = 0;
                                horas++;
                            }
                        }
                    }

                    if (milisegundos < 10) {
                        MS = "00"+milisegundos;
                    } else if (milisegundos < 100) {
                        MS = "0"+milisegundos;
                    } else {
                        MS = Integer.toString(milisegundos);
                    }

                    if (segundos < 10) {
                        S = "0"+segundos;
                    } else {
                        S = Integer.toString(segundos);
                    }

                    if (minutos < 10) {
                        M = "0"+minutos;
                    } else {
                        M = Integer.toString(minutos);
                    }

                    if (horas < 10) {
                        H = "0"+horas;
                    } else {
                        H = Integer.toString(horas);
                    }

                    cadena = H+":"+M+":"+":"+S+":"+MS;
                    tiempo.setText(cadena);
                    panel.repaint();

                }   
            } catch (Exception w) {
                w.printStackTrace();
            }
        }
    };

    iniciar.setText("Iniciar");
    iniciar.addActionListener(escucha);

    pausar.setText("Pausar");
    pausar.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            condición = false;
            pausar.setEnabled(false);
            iniciar.setEnabled(true);
            iniciar.setText("Reanudar");
        }
    });

    reiniciar.setText("Reiniciar");
    reiniciar.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {

        }
    });

    rb1.setText("Cronómetro");
    rb1.setSelected(true);
    rb1.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
           alredySelected = false;
        }
    });
    rb2.setText("Cuenta regresiva");
    rb2.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            try {
                if (rb2.isSelected() && alredySelected==false) {
                    alredySelected = true;
                    String temp = JOptionPane.showInputDialog(frame, "Ingrese el número en segundos:");
                    while (temp.equals("")) {
                        JOptionPane.showMessageDialog(frame, "¡Debe ingresar un valor!", "Error", JOptionPane.ERROR_MESSAGE);
                        temp = JOptionPane.showInputDialog(frame, "Ingrese el número en segundos:");
                    }
                    horas = Integer.parseInt(temp);
                }
            } catch (java.lang.NumberFormatException x) {
                JOptionPane.showMessageDialog(frame, "¡Solo debe ingresar números!", "Error", JOptionPane.ERROR_MESSAGE);
                rb1.setSelected(true);
                alredySelected = false;
            } catch (java.lang.NullPointerException x) {
                rb1.setSelected(true);
                alredySelected = false;
            }
        }
    });
    bg.add(rb1);
    bg.add(rb2);
    panel_opciones.setLayout(new FlowLayout());
    panel_opciones.add(rb1);
    panel_opciones.add(rb2);

}

}

2 个答案:

答案 0 :(得分:3)

基本上,你违反了Swing的单线程特性。

  1. 永远不要从事件调度线程以外的任何线程更新UI
  2. 永远不会阻止事件调度线程
  3. 执行第二步将阻止EDT更新UI(以及响应事件和其他重要事项)

    请查看The Event Dispatching Thread了解详情

    在你的情况下,Swing Timer就足够了。有关详细信息,请查看Swing Timer

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.ItemEvent;
    import java.awt.event.ItemListener;
    import javax.swing.ButtonGroup;
    import javax.swing.JButton;
    import javax.swing.JCheckBox;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JRadioButton;
    import javax.swing.JTextField;
    import java.awt.Toolkit;
    import javax.swing.SwingConstants;
    import java.awt.Font;
    import javax.swing.SwingUtilities;
    import javax.swing.Timer;
    
    public class Principal {
    
        public int horas = 0, minutos = 0, segundos = 0, milisegundos = 0;
        public String cadena = "00:00:00:00", MS, S, M, H;
        public boolean condición = true, alredySelected = false;
    
        private Timer timer;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Principal();
                }
            });
        }
    
        public Principal() {
            JFrame frame = new JFrame();
            JPanel panel = new JPanel();
            JPanel panel_botones = new JPanel();
            JPanel panel_opciones = new JPanel();
            JRadioButton rb1 = new JRadioButton();
            JRadioButton rb2 = new JRadioButton();
            ButtonGroup bg = new ButtonGroup();
            JButton iniciar = new JButton();
            JButton pausar = new JButton();
            JButton reiniciar = new JButton();
            Dimension minimumSize = new Dimension(400, 200);
            JTextField tiempo = new JTextField(cadena);
            JCheckBox siempreArriba = new JCheckBox();
    
            tiempo.setFont(new Font("Arial", Font.BOLD, 45));
            tiempo.setHorizontalAlignment(SwingConstants.CENTER);
            tiempo.setEditable(false);
            tiempo.setColumns(11);
    
            pausar.setEnabled(false);
            reiniciar.setEnabled(false);
    
            frame.setTitle("Cronómetro");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
    //        frame.setIconImage(Toolkit.getDefaultToolkit().getImage(Principal.class.getResource("/icons/icono.png")));
    
            panel.setLayout(new BorderLayout());
            panel.add(panel_botones, BorderLayout.PAGE_END);
            panel.add(panel_opciones, BorderLayout.PAGE_START);
            panel.add(tiempo, BorderLayout.CENTER);
            panel.add(siempreArriba, BorderLayout.EAST);
    
            panel_botones.setLayout(new FlowLayout());
            panel_botones.add(iniciar);
            panel_botones.add(pausar);
            panel_botones.add(reiniciar);
    
            siempreArriba.setText("Siempre arriba");
            siempreArriba.addItemListener(new ItemListener() {
                public void itemStateChanged(ItemEvent e) {
                    if (siempreArriba.isSelected()) {
                        frame.setAlwaysOnTop(true);
                    } else {
                        frame.setAlwaysOnTop(false);
                    }
                }
            });
    
            timer = new Timer(1, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    milisegundos++;
                    if (milisegundos > 999) {
                        milisegundos = 0;
                        segundos++;
                        if (segundos > 59) {
                            segundos = 0;
                            minutos++;
                            if (minutos > 59) {
                                minutos = 0;
                                horas++;
                            }
                        }
                    }
    
                    if (milisegundos < 10) {
                        MS = "00" + milisegundos;
                    } else if (milisegundos < 100) {
                        MS = "0" + milisegundos;
                    } else {
                        MS = Integer.toString(milisegundos);
                    }
    
                    if (segundos < 10) {
                        S = "0" + segundos;
                    } else {
                        S = Integer.toString(segundos);
                    }
    
                    if (minutos < 10) {
                        M = "0" + minutos;
                    } else {
                        M = Integer.toString(minutos);
                    }
    
                    if (horas < 10) {
                        H = "0" + horas;
                    } else {
                        H = Integer.toString(horas);
                    }
    
                    cadena = H + ":" + M + ":" + S + ":" + MS;
                    tiempo.setText(cadena);
                    panel.repaint();
    
                }
            });
    
            ActionListener escucha = new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    milisegundos = 0;
                    iniciar.setEnabled(false);
                    pausar.setEnabled(true);
                    reiniciar.setEnabled(true);
                    rb1.setEnabled(false);
                    rb2.setEnabled(false);
    
                    timer.start();
    
    //                try {
    //                    while (true) {
    //                        milisegundos++;
    //                        if (milisegundos > 999) {
    //                            milisegundos = 0;
    //                            segundos++;
    //                            if (segundos > 59) {
    //                                segundos = 0;
    //                                minutos++;
    //                                if (minutos > 59) {
    //                                    minutos = 0;
    //                                    horas++;
    //                                }
    //                            }
    //                        }
    //
    //                        if (milisegundos < 10) {
    //                            MS = "00" + milisegundos;
    //                        } else if (milisegundos < 100) {
    //                            MS = "0" + milisegundos;
    //                        } else {
    //                            MS = Integer.toString(milisegundos);
    //                        }
    //
    //                        if (segundos < 10) {
    //                            S = "0" + segundos;
    //                        } else {
    //                            S = Integer.toString(segundos);
    //                        }
    //
    //                        if (minutos < 10) {
    //                            M = "0" + minutos;
    //                        } else {
    //                            M = Integer.toString(minutos);
    //                        }
    //
    //                        if (horas < 10) {
    //                            H = "0" + horas;
    //                        } else {
    //                            H = Integer.toString(horas);
    //                        }
    //
    //                        cadena = H + ":" + M + ":" + ":" + S + ":" + MS;
    //                        tiempo.setText(cadena);
    //                        panel.repaint();
    //
    //                    }
    //                } catch (Exception w) {
    //                    w.printStackTrace();
    //                }
                }
            };
    
            iniciar.setText("Iniciar");
            iniciar.addActionListener(escucha);
    
            pausar.setText("Pausar");
            pausar.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    condición = false;
                    pausar.setEnabled(false);
                    iniciar.setEnabled(true);
                    iniciar.setText("Reanudar");
                    timer.stop();
                }
            });
    
            reiniciar.setText("Reiniciar");
            reiniciar.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    timer.start();
                }
            });
    
            rb1.setText("Cronómetro");
            rb1.setSelected(true);
            rb1.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    alredySelected = false;
                }
            });
            rb2.setText("Cuenta regresiva");
            rb2.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    try {
                        if (rb2.isSelected() && alredySelected == false) {
                            alredySelected = true;
                            String temp = JOptionPane.showInputDialog(frame, "Ingrese el número en segundos:");
                            while (temp.equals("")) {
                                JOptionPane.showMessageDialog(frame, "¡Debe ingresar un valor!", "Error", JOptionPane.ERROR_MESSAGE);
                                temp = JOptionPane.showInputDialog(frame, "Ingrese el número en segundos:");
                            }
                            horas = Integer.parseInt(temp);
                        }
                    } catch (java.lang.NumberFormatException x) {
                        JOptionPane.showMessageDialog(frame, "¡Solo debe ingresar números!", "Error", JOptionPane.ERROR_MESSAGE);
                        rb1.setSelected(true);
                        alredySelected = false;
                    } catch (java.lang.NullPointerException x) {
                        rb1.setSelected(true);
                        alredySelected = false;
                    }
                }
            });
            bg.add(rb1);
            bg.add(rb2);
            panel_opciones.setLayout(new FlowLayout());
            panel_opciones.add(rb1);
            panel_opciones.add(rb2);    
    
            frame.add(panel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
    }
    

    就我个人而言,我不喜欢像Timer这样增加一个计数器,因为Timer是不准确的,更好的解决方案是保持一个起点并计算它们之间的差异当Timer滴答和这一点,但是,那就是我

答案 1 :(得分:0)

首先,你循环耗尽你的CPU,变量毫秒增加,当达到999时减少,不间断,CPU永远不会休息休息,每当毫秒值改变时,你要求面板重新绘制,它是你的CPU无法完成这项任务。

其次,毫秒不会按照你期望的方式工作,除非你的CPU在每个时钟周期都需要1毫秒,甚至连古董电脑都不会那么慢。

你应该用Timer(Google Java Timer示例)替换你的while循环,这样你的代码每毫秒运行一次,你的CPU可以单手操作。 :)