簡體   English   中英

當我嘗試無休止地更新JTextField時,為什么程序會凍結?

[英]Why does my program freeze when I try to update a JTextField with an endless while?

我正在嘗試制作天文鍾,但是當我單擊“ Iniciar(start)”時,程序凍結。 這是給我帶來問題的部分:

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(並響應事件和其他重要事件)

查看事件調度線程以獲取更多詳細信息

在您的情況下,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滴答聲與該時間點之間的差,但是,這就是我

首先,當循環使CPU耗盡時,可變毫秒數會增加,而直到999時可變毫秒數會不斷減少,不間斷,CPU永不休息,並且每次更改毫秒值時,您都要求面板重新粉刷,這是不可能完成的任務您的CPU可以做到這一點。

其次,毫秒不會像您期望的那樣工作,除非您的CPU在每個時鍾周期花費1毫秒,否則即使是老式計算機也不會那么慢。

您應該用Timer(例如Google Java Timer示例)替換while循環,以便您的代碼每毫秒運行一次,您的CPU可以處理一次。 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM