invokeAndWait 方法 in SwingUtilities

2022-09-01 20:04:36

请解释 SwingUtilities 中的 invokeAndWait() 方法。我无法理解这一点。解释得很清楚。如果您尝试使用示例,这将有很大的帮助。

编辑以添加@noob问题的扩展:

有什么不清楚的?

下面是一个修改后的用法示例:

import javax.swing.SwingUtilities;

public class InvokeAndWaitStuff 
{
    public static void main(String[] args)
    {
        final Runnable doHelloWorld = new Runnable() {
             public void run() {
                 System.out.println("Hello World on " + Thread.currentThread());
             }
         };

         Thread appThread = new Thread() {
             public void run() {
                 try {
                     SwingUtilities.invokeAndWait(doHelloWorld);
                 }
                 catch (Exception e) {
                     e.printStackTrace();
                 }
                 System.out.println("Finished on " + Thread.currentThread());
             }
         };
         appThread.start();
    }
}

输出:

Hello World on Thread[AWT-EventQueue-0,6,main]
Finished on Thread[Thread-0,5,main]

为什么这很重要?

使 doHelloWorld.run() 在 AWT 事件调度线程上同步执行。此调用将阻塞,直到所有挂起的 AWT 事件都已处理完毕,并且(然后)doHelloWorld.run() 返回。当应用程序线程需要更新 GUI 时,应使用此方法。

据我所知,这基本上是一个瓶颈,它迫使GUI更新由单个线程同步执行,而不是由多个线程异步执行,这可能不安全。


答案 1

要了解其作用,首先需要了解 Swing 的事件/线程模型。invokeAndWait()

基本上,以任何方式影响GUI的所有事情都必须发生在单个线程上。这是因为经验表明,多线程 GUI 不可能正确。

在 Swing 中,此特殊的 GUI 线程称为事件调度线程或 EDT。一旦显示 Swing 顶级组件,它就会启动,它基本上是一个工作线程,它具有一个FIFO事件对象队列,它一个接一个地执行。

当需要绘制或更新 Swing GUI 时,JRE 会在 EDT 队列中放置一个事件。导致调用侦听器的用户操作作为 EDT 队列上的事件启动。而且(这是重要的部分)程序所做的更改 GUI 的所有操作(如注册侦听器、添加/删除 GUI 组件或更改 GUI 显示的模型数据)都必须放在 EDT 队列中,否则 GUI 可能会损坏。

现在完成:invokeAndWait() 将传递给它的 Runnable 放入 EDT 事件队列中,并等待 EDT 执行它。当非 GUI 线程需要执行影响 GUI 的操作,但也需要等到实际完成才能继续时,应使用此方法。如果您只想做一些影响 GUI 但并不关心它何时完成的事情,则应改用 。invokeLater()


答案 2

我在JTable中遇到了类似的问题。该程序在“scrollRectToVisible”方法中的某个地方被阻止。我已通过将调用包装在调用Later调用中来替换该调用。invokeAndWait没有解决我的块问题。

    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            table.scrollRectToVisible(r);
        }

    });

推荐