Java 在线程完成后调用函数
我正在使用Jsch编写一个Sftp客户端程序。我使用JProgressBars来显示上传和下载的进度。我的GUI包含与我的工作目录中的文件相对应的按钮。删除文件时,我更新了gui以向用户提供反馈:Java 在线程完成后调用函数,java,multithreading,swing,sftp,jprogressbar,Java,Multithreading,Swing,Sftp,Jprogressbar,我正在使用Jsch编写一个Sftp客户端程序。我使用JProgressBars来显示上传和下载的进度。我的GUI包含与我的工作目录中的文件相对应的按钮。删除文件时,我更新了gui以向用户提供反馈: void update() { panel.removeAll(); addToPanel(ls(channelsftp, sftpWorkingDir)); validate(); } 这是使用my ls函数返回当前workingDir中的所有文件。addToPanel将处
void update() {
panel.removeAll();
addToPanel(ls(channelsftp, sftpWorkingDir));
validate();
}
这是使用my ls函数返回当前workingDir中的所有文件。addToPanel将处理面板上的“输入到输出”按钮。这对于删除文件非常有效。但是,我希望在上传完成后调用相同的更新函数。由于upload以JProgressBar的形式向我提供图形反馈,其功能已转移到线程:
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();
}
}
});
因此,当用户在这个JFileChooser中单击OK之后,上传就开始了。以下是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);
}
}
}
SystemOutpressMonitor是一个在Jsch中处理数据传输的类。
我尝试使用Thread.join()和CountDownLatch。两者都阻止了我的JProgressBar更新。有不同的解决方案吗?解决方案是使用回调方法或机制。因为这是一个Swing问题,所以在一个线程中使用SwingWorker,而不是Runnable,它提供了两种潜在的方法
- 当Swing事件线程的worker中的
done()
- 或者将PropertyChangeListener添加到SwingWorker,侦听“state”属性,并在新值为
时做出反应李>SwingWorker.StateValue.DONE
setProgress(int-value)
来更新此属性。然后在侦听器中,使用此值更新JProgressBar
例如(请注意,代码尚未测试,如果出现错误,请道歉):
然后使用它:
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();
}
}
这对我没用。实际上SystemOutpressMonitor已经有一个end()函数,该函数在进程完成后调用。我可以在那里调用update,但是更新需要是静态的。它不可能是静态的,因为我在那里打电话。将对扩展JFrame的Navigator类调用validate()。我遗漏了什么吗?@RonnyBrandt:那么你的问题并不像你在问题中完全描述的那样,因为这确实显示了一个有效的解决方案,当后台线程完成时,如何在Swing事件线程上调用Swing代码。如果这不起作用,那么你需要更新你的问题,主要是通过创建和发布一个有效的。对于您的MCVE,请使用
Thread.sleep
模拟长期运行的后台进程,因为这将允许我们运行您的代码,而不需要我们没有的文件和依赖项。是的,它现在正在工作。我的解决方案是使用Navigator调用UploadUtil。这可以解决静态/非静态问题。。。谢谢你的帮助;)@罗尼布兰特:我很高兴你把事情解决了。我必须指出,不应该存在静态/非静态问题。除了主方法之外的所有方法,也许还有一些单例,都应该在实例(非静态)世界中运行。如果您对此有疑问,它建议您的代码可以从重新设计中受益。祝你好运一切都在“实例”世界中运行。我的main方法只创建另一个类的一个对象,它只有两行代码。但是我创建了一个UploadUtil对象。UploadUtil无法在导航器上调用validate()。但是当我实例化UploadUtil时,我可以传递我的Navigator对象。我应该重新设计这个吗?
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
}
}
}
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();
}
}