java - 当我尝试无休止地更新 JTextField 时,为什么我的程序会卡住?

标签 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);

}

}

最佳答案

基本上,您违反了 Swing 的单线程性质。

  1. 切勿从事件调度线程以外的任何线程更新 UI
  2. 永远不要阻塞事件调度线程

执行第二个操作将阻止 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 滴答时间与此时点之间的差异,但是,这就是我

关于java - 当我尝试无休止地更新 JTextField 时,为什么我的程序会卡住?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41584711/

相关文章:

java - Ionic 构建错误 : Could not create service of type ScriptPluginFactory using BuildScopeServices. createScriptPluginFactory()

java - 如何使用 keycloak 保护 angular/spring 应用程序?

java - 嵌入式 Jetty WebAppContext 中的通配符支持

java - 如何使面板数 = for 循环中的迭代次数

php - 如何停止 PHP 脚本?

java - 在图中构建随机哈密顿路径

java - 如何动态调整 JFrame 的大小以包含具有不同内容大小的 JPanel?

java - 如何使用BufferedImage在JPanel上绘制多条曲线?

Java while循环括号函数

python - 'while'循环出错后如何返回特定点