Java: как запустить диалог пользовательского интерфейса из другого потока, например, для Authenticator
Моя проблема в двух словах: мое приложение с графическим интерфейсом должно выполнять длительную сетевую загрузку. Загрузка осуществляется в отдельном потоке. Возможно, что удаленный сайт потребует аутентификации, поэтому я хочу определить Authenticator, который открывает диалоговое окно "введите ваше имя пользователя и пароль". Я понимаю, что этот диалог должен быть запущен из потока пользовательского интерфейса.
Я уверен, что я не первый человек, который делает это. Какова лучшая практика для того, чтобы фоновый поток запускал диалог в потоке пользовательского интерфейса и блокировал, пока этот диалог не был закрыт?
ps фоновый поток очень большой и делает гораздо больше, чем просто скачивает файл из сети. Другими словами, на данный момент, вероятно, нецелесообразно конвертировать его в SwingWorker, и в любом случае, я не уверен, как бы я решил эту проблему с помощью SwingWorker.
3 ответа
Вам нужен 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, если нет, то SwingUtilites.invokeLater() ничего не уведомляет, любое всплывающее окно будет отображаться, может быть, просто пустой прямоугольник
1/ создать EDT с помощью java.swing.Action
2 / отладить эту идею trashgod Я думаю, что эта логика является правильной и лучше всего для этого
Для протокола, вот мое окончательное решение, основанное на ответе Эндрю:
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;
}
}
};