1

I am trying to implement an image using the method below, so that when the send action is performed, the GIF image should show within a specified time(As implemented by the threadRunner pause method).

The problem is it doesn't show. And on testing, when I disable the stop() it appears at the same time as delIveryReport Textarea which shouldn't be. How do I solve this.

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


        } 

THREADRUNNER

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);
    } 
nnanna
  • 287
  • 4
  • 12

2 Answers2

2

It seems to me that your application is doing the actual work on the EDT, while your thread takes care of showing and hiding the progress label. I might be wrong, but if that is the case, then I'd recommend that you do the complete opposite of what you are doing. Updating SWING components should only be done from the EDT (Event Dispatch Thread) and no other threads.

If this is a SWING desktop application, then my recommendation would be that you take a look at SwingWorker which is a class that is specifically designed to handle long running tasks withough blocking the EDT. You could then do something like outlined below (my code might not compile 100%, but it should give you an idea of what i mean.

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.
    }
}

As for your question : just set the animated gif as the JLabel's icon - and SWING should take care of showing it. As long as your SMS sending code runs on another thread, SWING should happily be able to render the GIF animations without being blocked by the SMS sending code.

sbrattla
  • 5,274
  • 3
  • 39
  • 63
  • trying to implement this as said. but keeps giving errors. I get the logic. But just dont know in what way I could implement it. Pls could you be more explicit – nnanna Oct 11 '11 at 10:49
  • The above example is quite specific. Have you had a look at the stacktrace for the exceptions that are thrown? – sbrattla Oct 11 '11 at 10:58
  • Using this implementation gives the desired effect of the gif image. But I have a problem running the send SMS code. It is not of the same type as the doInBackground(it is a string type which needs to be in a for loop). And when I change the generic type for it to return a string I dont get the desired behaviour – nnanna Oct 11 '11 at 11:27
  • I know I might not make sense, but honestsly, I am really confused on hoe to do this – nnanna Oct 11 '11 at 11:28
  • You could have the return type (which in my example was Boolean) to be whatever type sms.response is. That is, you'll return sms.response from doInBackground() and then retrieve that value using get() in done(). The class "signature" would thus be SwingWorker, assuming that sms.response returns an object of type SMSRespons.e – sbrattla Oct 11 '11 at 11:45
  • I've updated my example to reflect your code even more. If you have more questions, then please generalise them so that others who have trouble getting things to work with EDT and threads can use this question as a reference. – sbrattla Oct 11 '11 at 11:55
1

you have to wrap label.setVisible(true); into invokeLater();

you have remove Thread.sleep(int) from Swing code because block EDT, then you have problem with Concurency in Swing, create a new void/clas.. with Thread started from Runnable, and inside this code block you can pausing process(es) by using Thread.sleep(int) and put here label.setVisible(true); wrapped into invokeLater(); too

animations or delaing any of actions in the Swing required usage of javax.swing.Timer

mKorbel
  • 109,525
  • 20
  • 134
  • 319