简体   繁体   中英

java: live updating upload progress in TextArea/JProgressBar using JSch SFTP

I have two class fils upload.java and transferProgress.java . upload.java makes applet GUI and uploads file to remote SSH server. transferProgress.java class gives transfer percentage. The upload percentage completed can be seen in console, but i wanted it to be seen on TextArea and on java progress bar. So i made transferProgress.java to inherit upload.java and append into TextArea .

My problem is, TextArea and JProgressBar do not get updated during the file transfer, but gets updated only when the file transfer is completed. After transfer completion, TextArea shows the log and JProgressBar get set to 100%. My code does not updates TextArea and JProgressBar during file transfer.

If i use setText() instead of append for updating TextArea, i can see real time progress update, but still ProgressBar do not get updated on real time.

I could not figure out where the problem is. I will be very thankful to your help.

upload.java

package biforce;
import java.applet.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*; 
import java.io.*; 


import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;


public class upload extends Applet
{

  String filename;
  int port = 22;
  String user = "root";
  String password = "mypass";
  String host = "192.168.0.5";
  String knownHostsFile = "/home/bishwo/.ssh/known_hosts";
  String sourcePath = "";
  String destPath = "/media/dfs/gwas/";

  JTextField txtField = new JTextField(20);
  static TextArea txtArea;
  static JProgressBar progressBar;

    @Override
  public void init(){

  // text Field     
  txtField.setEditable(false);
  txtField.setText("");

  // text area
  txtArea = new TextArea(4,40);
  txtArea.setEditable(false);

  // JprogressBar
  progressBar = new JProgressBar(0, 100);
  progressBar.setValue(0);
  progressBar.setStringPainted(true);

  // Label
  JLabel fileLabel = new JLabel("File");

  // buttons
  JButton upload = new JButton( "Upload" );
  JButton browse = new JButton( "Browse" );

  // browse file to be uploaded
  browse.addActionListener( 
      new ActionListener()
      {
            @Override
        public void actionPerformed( ActionEvent ae )
        {
          JFileChooser fc = new JFileChooser();
          fc.setCurrentDirectory( new File( "/home/bishwo/Desktop/" ) );
          int returnVal = fc.showOpenDialog( upload.this ); 
          String filePath="";
          if ( returnVal == JFileChooser.APPROVE_OPTION )   
          {  
            File aFile = fc.getSelectedFile();  
            filePath = aFile.getAbsolutePath(); 
            filename = aFile.getName();
          }
          txtField.setText(filePath);
        }
      });
  // upload the browsed file
  upload.addActionListener( 
      new ActionListener()
      {
            @Override
        public void actionPerformed( ActionEvent ae )
        {

          if(txtField.getText().length()==0)
          {
              JOptionPane.showMessageDialog(upload.this,"Please select a file to upload.","Error", JOptionPane.ERROR_MESSAGE);
          }
          else
          {
            try
            {
                sourcePath=txtField.getText();
                JSch jsch = new JSch();
                jsch.setKnownHosts(knownHostsFile);
                Session session = jsch.getSession(user, host, port);
                session.setPassword(password);
                session.connect(); 

                ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp");
                sftpChannel.connect();

                txtArea.setText("Uploading..");
                transferProgress progress = new transferProgress();
                sftpChannel.put( sourcePath,destPath+filename, progress);      
                System.out.println("\nUpload Completed");  

                sftpChannel.exit();
                session.disconnect();
                JOptionPane.showMessageDialog(upload.this,"Upload completed successfully.","Info", JOptionPane.INFORMATION_MESSAGE);

            }
            catch(Exception e)
            {
                JOptionPane.showMessageDialog(upload.this,e,"Error", JOptionPane.ERROR_MESSAGE);
            }
          }
        }
      });

  add(fileLabel);
  add(txtField,"center");
  add(browse);
  add(upload);
  add(progressBar);
  add(txtArea);
  }

}

transferProgress.java

import com.jcraft.jsch.*;

public class transferProgress extends upload implements SftpProgressMonitor
{
    public double count=0;
    private int percentage;
    public double totalSize;
    private int lastPercentage;
    @Override
    public void init(int op, String src, String dest, long max) 
        {
        this.totalSize=max;
        }

    @Override
    public boolean count(long count) 
        {
        this.count += count;
        this.percentage = (int) ((this.count / this.totalSize) * 100.0);
        if (this.lastPercentage <= this.percentage - 5) 
            {
            this.lastPercentage= this.percentage;
            // setValue() does not work
            biforce.upload.progressBar.setValue(20);
            // append() does not work
            biforce.upload.txtArea.append(Integer.toString(this.percentage));
            // displays percentage completion on console
            System.out.println("Upload Completion "+this.percentage+" %");

            }
        return true;
        }

    @Override
    public void end() 
        {
        System.out.println("Total Copied "+this.percentage+" %");
        }
}

You need to update your progressbar in a seperate Thread.

I would suggest to let your Class transferProgress (Note: Class names should start with a capital letter) implement the Runnable Interface and then use the ExecutorService to start a new thread with this Class.

Eg

public class TransferProgress extends upload implements SftpProgressMonitor, Runnable {
    @Override
    public void run() {
       //update your progressbar here, basically the same as your count method
    }
}

public class upload extends Applet {
    //some code...
    upload.addActionListener( 
      new ActionListener()
       {
             @Override
             public void actionPerformed( ActionEvent ae )
             {
                 //some code....
                 //start a new thread here which executes your run method in the TransferProgress class
                 ExecutorService executor = Executors.newSingleThreadExecutor();
                 executor.submit(new TransferProgress());
                 //some code...
             }
       }
    );

}

You should never do long-running actions from the event dispatch thread (EDT), since the GUI is blocked during this time. You observed here an effect of this. The EDT is the thread which runs all action listeners, and also repaints your GUI objects. As long as an action listener is running, no other events will be dispatched, and also no painting will occur => you will see no updates on your progress bar or text area. (They will be updated once your action listener finishes, though.)

Thus, use a separate thread to upload the file, ie everything inside the else -block in the ActionListener, like in flash's answer.

Everything which updates the GUI then should be done in the EDT again, so use EventQueue.invokeLater (or SwingUtilities.invokeLater ) for the GUI-updating part:

EventQueue.invokeLater(new Runnable() { public void run() {
       biforce.upload.progressBar.setValue(20);
       biforce.upload.txtArea.append(Integer.toString(this.percentage));
}});

count() method from transferProgress class gives progress percentage 20 times until the file gets uploaded.

In my case SwingUtilities.invokeLater did not work out. I used SwingWorker, executed from upload class and it worked. (PS - i made progressBar in the class upload 'public')

public class uploadWorker extends SwingWorker<Integer, Integer>
{
    @Override
        protected Integer doInBackground() throws Exception
        {
                //some codes .....

                try{sftpChannel.put(upload.sourcePath,upload.destPath, new transferProgress()); }
               catch(Exception e){System.out.println(e);}

                Thread.sleep(1000);
                return 42;
        }

        protected void done()
        {

                System.out.print("done");

        }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM