Java:如何从另一个线程启动 UI 对话框,例如 Authenticator

发布于 2024-11-09 09:50:09 字数 285 浏览 0 评论 0原文

简而言之,我的问题是:我的 GUI 应用程序需要执行冗长的网络下载。下载是在单独的线程中处理的。远程站点可能需要身份验证,因此我想定义一个身份验证器来弹出“输入您的用户名和密码”对话框。我意识到这个对话框需要从 UI 线程运行。

我确信我不是第一个这样做的人。让后台线程在 UI 线程中启动对话框并阻塞直到该对话框被关闭的最佳实践是什么?

ps 后台线程非常大,并且不仅仅从网络下载文件。换句话说,目前将其转换为 SwingWorker 可能不切实际,而且无论如何,我也不确定如何从 SwingWorker 解决这个问题。

My problem in a nutshell: my GUI app needs to execute a lengthy network download. The download is handled in a separate thread. It's possible that the remote site will require authentication, so I want to define an Authenticator that pops up an "enter your username and password" dialog. I realize that this dialog needs to be run from the UI thread.

I'm sure I'm not the first person to do this. What is the best practice here for having a background thread launch a dialog in the UI thread, and block until that dialog is dismissed?

p.s. the background thread is very large and does a lot more than just download a file from the net. In other words, it's probably not practical at this point to convert it to a SwingWorker, and anyway, I'm not sure how I would solve this from a SwingWorker either.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

迷爱 2024-11-16 09:50:09

您需要 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
}

you need SwingUtlities.invokeLater to present the dialog, and a synchronize/notify object to 'pause' and wait for the user to respond.

Basically in your worker(non-gui) thread:

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
}
娇女薄笑 2024-11-16 09:50:09

Edward Falk 写道 实际上,看起来 invokeLater() 也会做我想要的事情

不,这是错误的,因为您必须计算 EDT 是否存在,并且如果存在正在运行的 EDT,则 SwingUtilites.invokeLater() 可以工作,如果没有,则 SwingUtilites.invokeLater() 不会收到任何通知,将显示任何弹出窗口,可能只是空矩形

1/使用 java.swing.Action

2/调试这个想法通过 垃圾神我认为这个逻辑是正确的并且是最适合的

Edward Falk wrote Actually, it looks like invokeLater() will also do what I want

no, that's wrong because you have to calculate that EDT exists, and SwingUtilites.invokeLater() works if is there running EDT, if not then SwingUtilites.invokeLater() nothing notified, any popup will be displaed, maybe just empty Rectangle

1/ create EDT by using java.swing.Action

2/ debug this idea by trashgod I think that that this logic is correct and best for that

誰ツ都不明白 2024-11-16 09:50:09

作为记录,这是我根据安德鲁的回答得出的最终解决方案:

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;
            }
        }
    };

For the record, here was my final solution, based on Andrew's answer:

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;
            }
        }
    };
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文