【问题标题】:How do I show a animated GIF image using a thread如何使用线程显示动画 GIF 图像
【发布时间】:2011-10-12 04:09:50
【问题描述】:

我正在尝试使用下面的方法实现一个图像,以便在执行发送操作时,GIF图像应该在指定的时间内显示(通过threadRunner暂停方法实现)。

问题是它没有显示。在测试中,当我禁用 stop() 时,它与不应该出现的 delLiveryReport Textarea 同时出现。我该如何解决这个问题。

 private void sendActionPerformed(java.awt.event.ActionEvent evt) {              

            threadRunner t = new threadRunner();
            String fone = "";
            SendSMS sms = new SendSMS();
            String[] arMSISDN = msisdn.split(",");
            for (int i = 0; i < arMSISDN.length; i++) {

                fone = arMSISDN[i];
                fone = fone.trim();
                try {

                    Cursor cursor = new Cursor(Cursor.WAIT_CURSOR);
                    setCursor(cursor);
                    t.pause(loading);

                    sms.sendSMS(user, pass, fone, senderIDString, msgString);


                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    Cursor normal = new Cursor(Cursor.DEFAULT_CURSOR);
                    setCursor(normal);
                    t.stop(loading);
                    deliveryReport.append(fone + ": " + sms.response + "\n");
                }

            }

    //        JOptionPane.showMessageDialog(rootPane, deliveryReport);
            deliveryReport.setVisible(true);
            jScrollPane2.setVisible(true);



            redo.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
            redo.setForeground(new java.awt.Color(223, 90, 46));
            redo.setText("Would you like to send another Message?");
            yes.setEnabled(true);
            no.setEnabled(true);
            yes.setText("Yes");
            no.setText("No");
            back.setEnabled(false);
            send.setEnabled(false);


        } 

线程运行者

public void pause(JLabel label){

        try {
            Thread.sleep(5000);
            label.setVisible(true);    
        } catch (InterruptedException ex) {
            Logger.getLogger(threadRunner.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void stop(JLabel l){
        l.setVisible(false);
    } 

【问题讨论】:

    标签: java multithreading swing


    【解决方案1】:

    在我看来,您的应用程序正在 EDT 上执行实际工作,而您的线程负责显示和隐藏进度标签。我可能是错的,但如果是这样的话,那么我建议你做与你正在做的事情完全相反的事情。更新 SWING 组件只能从 EDT(事件调度线程)完成,不能从其他线程完成。

    如果这是一个 SWING 桌面应用程序,那么我的建议是你看看 SwingWorker,这是一个专门设计用于处理长时间运行的任务而不会阻塞 EDT 的类。然后,您可以执行如下所述的操作(我的代码可能无法 100% 编译,但它应该让您了解我的意思。

    private void sendActionPerformed(java.awt.event.ActionEvent evt) {  
      //implement code to show progress label here
      SMSWorker w = new SMSWorker(user, pass, senderIdString, msgString, msisdn.split(","));
      w.execute();
    }
    
    public SMSWorker extends SwingWorker<Void, DeliveryReport> {
    
      private final String user;
      private final String pass;
      private final String senderIdString;
      private final String msgString;
      private final String[] arMSISDN;
    
      // this constructor runs on the current (EDT) thread.
      public SMSWorker(String user, String pass, String senderIdString, String msgString, String[] arMSISDN) {
        this.user = user;
        this.pass = pass;
        this.senderIdString = senderIdString;
        this.msgString = msgString;
        this.arMSISDN = arMSISDN;
      }
    
      // this function runs in a separate thread.
      public Boolean doInBackground() {
    
           // Instantiate SMS gateway client.
           SendSMS sms = new SendSMS();
    
           // Assuming a delivery report can be created like this.
           DeliveryReport deliveryReport = new DeliveryReport();
    
           for (int i = 0; i < arMSISDN.length; i++) {
    
                fone = arMSISDN[i];
                fone = fone.trim();
                try {
                    sms.sendSMS(user, pass, fone, senderIDString, msgString);
    
                } catch (Exception e) {
                    // you can notify users about exception using the publish() method.
    
                } finally {
                    deliveryReport.append(fone + ": " + sms.response + "\n");
                }
    
            }
    
            return deliveryReport;
    
      }
    
      // this function runs on the current (EDT) thread.
      public void done() {
        try {
          // synchronize worker thread with EDT.
          DeliveryReport deliveryReport = get();
        } catch (Exception e) {
          //implement code to notify user about errors here.
        } finally {
          //implement code to hide progress label here.
        }
    }
    

    至于您的问题:只需将动画 gif 设置为 JLabel 的图标 - 并且 SWING 应该注意显示它。只要您的 SMS 发送代码在另一个线程上运行,SWING 应该能够愉快地呈现 GIF 动画而不会被 SMS 发送代码阻塞。

    【讨论】:

    • 如前所述尝试实现这一点。但不断给出错误。我明白其中的逻辑。但只是不知道我可以用什么方式来实现它。请问你能更明确一点吗
    • 上面的例子很具体。您是否查看过堆栈跟踪中抛出的异常?
    • 使用这个实现可以得到所需的 gif 图像效果。但我在运行发送 SMS 代码时遇到问题。它与 doInBackground 的类型不同(它是一个字符串类型,需要在 for 循环中)。当我更改泛型类型 以使其返回字符串时,我没有得到所需的行为
    • 我知道我可能没有意义,但老实说,我真的很困惑锄头这样做
    • 您可以将返回类型(在我的示例中为布尔值)设置为 sms.response 的任何类型。也就是说,您将从 doInBackground() 返回 sms.response,然后在 done() 中使用 get() 检索该值。因此类“签名”将是 SwingWorker,假设 sms.response 返回一个 SMSRespons.e 类型的对象
    【解决方案2】:

    你必须将label.setVisible(true); 包装成invokeLater();

    你已经从 Swing 代码中删除了 Thread.sleep(int),因为阻塞了 EDT,那么你有 Concurency in Swing 的问题,创建一个新的 void/class.. 使用从 Runnable 开始的 Thread,在这个代码块中你可以使用Thread.sleep(int) 暂停进程并将label.setVisible(true); 放入invokeLater();

    Swing 中的动画或延迟任何动作都需要使用javax.swing.Timer

    【讨论】:

      猜你喜欢
      • 2011-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-09
      • 1970-01-01
      • 2015-12-18
      相关资源
      最近更新 更多