javamultithreadingswingsftpjprogressbar

Call a function after a Thread is completed


i'm writing a Sftp-client program using Jsch. I am using JProgressBars to display the Progress of Uploads and Downloads. My GUI contains Buttons according to the files in my Working Directory. When i delete a file i updated my gui to give the user a feedback:

void update() {
    panel.removeAll();
    addToPanel(ls(channelsftp, sftpWorkingDir));
    validate();
}

This is using my ls-function to return all Files in the current workingDir. addToPanel will process the lsEntries to output Buttons on the panel. This works great for deleting files. However, i want the same update-function to be called after an upload is completed. Since upload is giving me graphical feedback in the form of a JProgressBar its functionality was moved to a thread:

final JFileChooser uploadChooser = new JFileChooser();
    ulo.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent arg0) {
            int returnVal = uploadChooser.showOpenDialog(Navigator.this);
            if(returnVal == JFileChooser.APPROVE_OPTION) {
                String pathToUpload = uploadChooser.getSelectedFile().getAbsolutePath();
                Runnable uploadIt = new UploadUtil(pathToUpload, chacha);
                new Thread(uploadIt).start();
            }   
        }
    });

So after the user clicks on OK in this JFileChooser the upload starts. Here is UploadUtil:

public class UploadUtil implements Runnable{

    String paTU;
    ChannelSftp csftp;

    public UploadUtil(String pathToUl, ChannelSftp chaSftp) {
        paTU = pathToUl;
        csftp = chaSftp;
    }

    @Override
    public void run() {
        try {
            csftp.put(paTU, LoginAndFunctions.sftpWorkingDir, new SystemOutProgressMonitor());
        } catch (SftpException e) {
            Error errorUploading = new Error(e.toString()+"\nUploadpipe closed unexpectedly");
            errorUploading.setVisible(true);
        }
    }
}

SystemOutProgressMonitor is a class that processes datatransfer in Jsch. I tried using Thread.join() and CountDownLatch. Both prevented my JProgressBar from updating. Is there a different solution for it?


Solution

  • A solution is to use a call back method or mechanism. Since this is a Swing problem, use a SwingWorker, not a Runnable in a thread which gives you two potential ways

    Note that you can also add a PropertyChangeListener to the worker thread and listen to its progress property. Within the worker as it's updating your data, update this property by calling setProgress(int value) with a value from 0 to 100. Then in the listener, update your JProgressBar with this value.

    For example (Note that code not tested yet, so sorry if there are errors):

    public class UploadUtil extends SwingWorker<Void, Void> {
    
        String paTU;
        ChannelSftp csftp;
    
        public UploadUtil(String pathToUl, ChannelSftp chaSftp) {
            paTU = pathToUl;
            csftp = chaSftp;
        }
    
        @Override
        public void doInBackground() throws Exception {
            try {
                csftp.put(paTU, LoginAndFunctions.sftpWorkingDir, new SystemOutProgressMonitor());
            } catch (SftpException e) {
                Error errorUploading = new Error(e.toString()+"\nUploadpipe closed unexpectedly");
                errorUploading.setVisible(true);
            }
        }
    }
    

    A listener for your worker:

    class UploadUtilListener implements PropertyChangeListener {
        public void propertyChanged(PropertyChangeEvent e) {
            if (e.getNewValue() == SwingWorker.StateValue.DONE) {
                // do your code here that you want called when worker done
            }
        }
    }
    

    then to use it:

    public void actionPerformed(ActionEvent arg0) {
        int returnVal = uploadChooser.showOpenDialog(Navigator.this);
        if(returnVal == JFileChooser.APPROVE_OPTION) {
            String pathToUpload = uploadChooser.getSelectedFile().getAbsolutePath();
            UploadUtil uploadIt = new UploadUtil(pathToUpload, chacha);
            uploadIt.addPropertyChangeListener(new UploadUtilListener());
            uploadIt.execute();
        }   
    }