简而言之,我的问题是:我的GUI应用程序需要执行长时间的网络下载。下载是在一个单独的线程中处理的。远程站点可能需要身份验证,所以我想定义一个弹出"输入用户名和密码"对话框的Authenticator。我意识到这个对话框需要从UI线程运行。
我确信我不是第一个这样做的人。让后台线程在UI线程中启动一个对话框,并阻止该对话框直到该对话框被关闭,这里的最佳做法是什么?
p.s.后台线程非常大,所做的工作远不止从网上下载一个文件。换句话说,在这一点上,将其转换为SwingWorker可能是不现实的,无论如何,我也不确定如何从SwingWorkers解决这个问题。
您需要SwingUtlities.invokeLater来显示对话框,并需要一个同步/通知对象来"暂停"并等待用户响应。
基本上在您的工作线程(非gui)中:
final Object obj = new Object() ; // or something to receive your dialog's answer(s)
Runnable r = new Runnable() {
void run() {
Dialog d = new Dialog() ;
Button b = new JButton("ok") ;
b.addActionListener(new ActionListener() {
void actionPerformed(ActionEvent e) {
synchronize(obj) { // can lock when worker thread releases with wait
obj.notify() ; // signals wait
}
}
}) ;
}
} ;
synchronize( obj ) {
SwingUtilites.invokeLater(r) ; // executs r's run method on the swing thread
obj.wait() ; // releases obj until worker thread notifies
}
Actually, it looks like invokeLater() will also do what I want
不,这是错误的,因为你必须计算EDT存在,并且SwingUtilites.invokeLater()在有运行EDT的情况下工作,如果没有,则SwingUtilits.invokeLater()没有任何通知,任何弹出窗口都将被显示,可能只是空矩形
1/使用java.swing.Action 创建EDT
2/通过垃圾神调试这个想法我认为这个逻辑是正确的,最适合
这里是我的最终解决方案,基于Andrew的答案:
final Authenticator authenticator =
new Authenticator() {
@Override
public PasswordAuthentication getPasswordAuthentication() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
// Launch the GUI dialog
queryUsernamePassword(getRequestingHost(), getRequestingPrompt());
}
});
if (username == null)
return null;
return new PasswordAuthentication(username,
password.toCharArray());
} catch (Exception e) {
return null;
}
}
};