【问题标题】:jFrames are got freeze by this code? (code attached) : Netbeans 8.2jFrames被这段代码冻结了吗? (附代码):Netbeans 8.2
【发布时间】:2017-07-12 16:31:17
【问题描述】:

我在我的 Java 应用程序中遇到一个问题,当通过单击 jButton 打开新的 jFrames 时,会出现一点点冻结并在其打开后(冻结时间 1-2 分钟/3 分钟)。我还找不到发生了什么问题。但我对以下附加代码有一些疑问。该代码用于获取系统时间和日期并显示所有 jFrames。所以这段代码在所有的jFrames中。现在我的问题是,这段代码是否发生了这种冻结..?或者可能有任何其他原因..?如果这段代码有任何错误,请告诉我……我正在使用 NETbeans 8.2。提前致谢。

代码:

public AdminHome() {
    initComponents();

    new Thread(new Runnable() {
        @Override
        public void run() {

            while (true) {
            Date d=new Date();

            SimpleDateFormat sd=new SimpleDateFormat("yyyy - MM - dd");
            String s =  sd.format(d);
            String s1 = d.toString();
            String ar[]=s1.split(" ");

            jLbl_Date.setText(s);  
            jLbl_Time.setText(ar[3]);
            }  
        }
    }).start();

}

【问题讨论】:

    标签: java freeze netbeans-8.2


    【解决方案1】:

    您可能创建了一个单独的线程,但所有 UI 更新都源于 AWT 线程。因此,该线程非常频繁地调用jLbl_date.setText()jLbl_time.setText() 方法实际上直接阻塞了AWT 线程。

    尝试在jLbl_Time.setText() 之后添加sleep(1000)

    【讨论】:

    • 另外,setText 调用应该是SwingUtilities.InvokeLatered。
    • 是的,如果我错了,请纠正我,但 AWT 不会像 JavaFX 那样限制多线程 UI 访问。
    • @Subhranil,tnx 为您解答。我试过你现在说的。但它显示错误。请你可以在这里修改我的代码和评论...?它对我很有用。
    • JLabel 是 Swing,不应被除事件调度线程之外的任何线程修改。
    • 你好@Colin__s,你说答案我没听懂。请您解释一下修改我的代码...?它对我更有帮助。我只是java的初学者...
    【解决方案2】:

    这两个调用:

    jLbl_Date.setText(s);  
    jLbl_Time.setText(ar[3]);
    

    必须在 EDT(事件调度线程)上发生,因为必须从 EDT 操作 GUI 组件。您可以使用 SwingUtilities 将它们包装在 EDT 上:

    SwingUtilities.invokeLater(() -> {
        Date d=new Date();
    
        SimpleDateFormat sd=new SimpleDateFormat("yyyy - MM - dd");
        String s =  sd.format(d);
        String s1 = d.toString();
        String ar[]=s1.split(" ");
    
        jLbl_Date.setText(s);  
        jLbl_Time.setText(ar[3]);
    });
    

    但是,问题仍然存在。由于您的线程在更新标签之间不会休眠,因此您将使用更新请求淹没 EDT,从而导致您的 GUI 再次冻结。您可以通过在更新标签后添加 Thread.sleep(1000); 来解决此问题。

    更优雅的方法是使用摇摆计时器而不是线程:

    Timer timer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Date d=new Date();
    
                SimpleDateFormat sd=new SimpleDateFormat("yyyy - MM - dd");
                String s =  sd.format(d);
                String s1 = d.toString();
                String ar[]=s1.split(" ");
    
                jLbl_Date.setText(s);  
                jLbl_Time.setText(ar[3]);
            }
    });            
    timer.setInitialDelay(0);
    timer.start();
    

    摆动计时器负责确保在 EDT 上执行带有 actionPerformed 方法的代码。它还有一个额外的优势,它可以在需要时合并事件 - 另一个机制来防止事件淹没 EDT。

    【讨论】:

    • 你打败了我! +1
    【解决方案3】:

    您似乎创建了一个线程来运行无限循环来更新某些日期和时间字段。这不是实现您想要做的事情的好方法。

    更好的解决方案是使用具有较短间隔的javax.swing.Timer,并从附加的操作侦听器更新您的 UI。

    ActionListener timerListener = new ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            Date d=new Date();
    
            SimpleDateFormat sd=new SimpleDateFormat("yyyy - MM - dd");
            String s =  sd.format(d);
            String s1 = d.toString();
            String ar[]=s1.split(" ");
    
            jLbl_Date.setText(s);  
            jLbl_Time.setText(ar[3]);
        }
    };
    
    Timer t = new javax.swing.timer(1000, timerListener).start();
    

    类似上面的东西应该可以解决问题。这为您省去了跨越线程边界来更新 UI 的麻烦,并且与您之前的解决方案相比,将大大减少 CPU 负载。

    【讨论】:

    • 我添加了你的代码。但是出错了,这个jframe也没有运行......它说“没有主要方法”在这里附加了你在我的代码中的代码:
    • 公共 AdminStudent() { initComponents(); ActionListener timerListener = new ActionListener { public void actionPerformed(ActionEvent e) { Date d=new Date(); SimpleDateFormat sd=new SimpleDateFormat("yyyy - MM - dd");字符串 s = sd.format(d);字符串 s1 = d.toString();字符串 ar[]=s1.split(" "); jLbl_Date.setText(s); jLbl_Time.setText(ar[3]); } } 定时器 t = new javax.swing.timer(1000, timerListener).start(); }
    • 我错过了动作监听器末尾的;
    猜你喜欢
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 2018-07-02
    • 2018-12-08
    • 2018-08-01
    • 2017-03-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多