【问题标题】:Trouble with SwingUtilities.invokeLater() updating GUISwingUtilities.invokeLater() 更新 GUI 出现问题
【发布时间】:2013-04-23 06:15:27
【问题描述】:

我整天都在尝试不同的变化,但收效甚微。有人可以帮忙解释我做错了什么吗?我只是线程方面的初学者。

private JTextArea text = new JTextArea();
private JButton button = new JButton("Cancel");
    public StatusFrame() {
        text.setEditable(false);
        this.add(text);
        this.add(button, BorderLayout.EAST);
        this.setSize(new Dimension(150, 100));
        this.setVisible(true);
    }

    public void updateStatus(String textIn) {
        text.setText(textIn);
    }

    public JButton getButton() {
        return button;
    }

在另一个类中,我正在调用可能需要一段时间才能完成的方法。我希望能够调用 StatusFrame.updateStatus() 方法来让用户了解进度。 这就是我所拥有的:

someMethod() {
    // prevent GUI from freezing using threads
    final Runnable r = new Runnable() {
        public void run() {
            status = new StatusFrame();
        }
    };
    SwingUtilities.invokeLater(r);

//do something 
    status.update("process 1 completed");
//do something else
    status.updateStatus("Process 2 completed");
}

框架出现,但运行/处理后的代码似乎没有运行/处理。它只是停止/阻止/某事。但 GUI 仍然处于活动状态

感谢您的建议。

P.S.:我尝试过使用invokeAndWait() 方法,但再次不确定我是否以正确的方式进行操作。现在最好快速修复,因为我还没有学到很多关于线程的知识。欢迎任何指示。

【问题讨论】:

  • 如需尽快获得更好的帮助,请发帖SSCCE

标签: java multithreading swing user-interface concurrency


【解决方案1】:

你的概念倒退了。

这是你的代码

someMethod() {
    // prevent GUI from freezing using threads
    final Runnable r = new Runnable() {
        public void run() {
            status = new StatusFrame();
        }
    };
    SwingUtilities.invokeLater(r);

//do something 
    status.update("process 1 completed");
//do something else
    status.updateStatus("Process 2 completed");

您应该在一个线程中执行长时间运行的代码,并使用 SwingUtilities invokeLater 方法更新 GUI。

someMethod() {
    // prevent GUI from freezing using threads
    final Runnable r = new Runnable() {
        public void run() {
            status = new StatusFrame();
        }
    };
    new Thread(r).start();

// inside the StatusFrame
//do something 
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            update("process 1 completed");
        }
    );

 //do something else sometime later
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
             update("Process 2 completed");
        }
    );

我不知道我的回答是否清楚。

  1. 在启动 Java 应用程序时执行 SwingUtilities.invokeLater 以确保 Swing 组件位于事件调度线程 (EDT) 上。
  2. 从 EDT,将长时间运行的进程作为可运行线程调用。
  3. 在可运行线程中,由于您不在 EDT 上,因此在更新 Swing 组件时执行 SwingUtilities.invokeLater。这可确保在 EDT 上更新 Swing 组件。

每个 Swing 应用程序都应该以这样的类开头:

import javax.swing.SwingUtilities;

import com.ggl.text.entry.model.TextEntryModel;
import com.ggl.text.entry.view.TextEntryFrame;

public class TextEntry implements Runnable {

    @Override
    public void run() {
        new TextEntryFrame(new TextEntryModel());
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TextEntry());
    }

}

这个类做了 3 件事。

  1. 构造 GUI 数据模型。
  2. 构造 GUI JFrame。
  3. 确保 Swing 组件位于 EDT 上。

【讨论】:

  • 谢谢一个问题。我在处理长时间运行代码的线程中创建的可运行对象上调用 invokeeLater()。问题是当在invokeLater() 中执行runnable 时,它​​似乎完成了长时间运行的代码的运行。如何让它立即运行传递给 invokeLater() 的可运行对象,以便及时更新 GUI。
  • 在 Runnable 的构造函数中传递一个 JFrame 类的实例和一个 GUI 模型类的实例。
  • 很抱歉刚刚看到我的问题并意识到它没有多大意义。我想问的是:我在威胁 t1 中有一个长时间运行的代码。在代码中,它使用 invokeLater() 来更新 GUI。问题是在 t1 完成之前,在 invokeLater() 中运行的进程似乎不会发生。如何让在 invokeLater() 方法中运行的进程(即 GUI 更新)立即发生?
  • 很抱歉刚刚看到我的问题并意识到它没有多大意义。我想问的是:我在威胁 t1 中有一个长时间运行的代码。在代码中,它使用 invokeLater() 来更新 GUI。问题是在 t1 完成之前,在 invokeLater() 中运行的进程似乎不会发生。如何让在 invokeLater() 方法中运行的进程(即 GUI 更新)立即发生?
  • 您可以使用 invokeAndWait 方法,但我不建议这样做。当您调用Later 时,您告诉GUI 在可以更新时进行更新。您还必须确保您在 invokeLater Runnable 中执行的命令确实会更新和重绘 GUI。
【解决方案2】:

Concurrency in Swing

您可能会发现使用 Swing Worker 更容易使用,因为它使用 Thread 并且具有允许您正确更新 GUI 的方法。

【讨论】:

    【解决方案3】:

    您还需要在 EDT 上调用更新。我建议睡在主线程上,让 GUI 有机会在任何其他工作之前出现:

    someMethod() {
        // prevent GUI from freezing using threads
        Runnable r = new Runnable() {
            public void run() {
                status = new StatusFrame();
            }
        };
        SwingUtilities.invokeLater(r);
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
        }
    
    //do something
        r = new Runnable() {
        public void run() {
                status.update("process 1 completed");
            }
        };
        SwingUtilities.invokeLater(r);
    
    
    //do something else
     r = new Runnable() {
        public void run() {
                status.update("Process 2 completed");
            }
        };
        SwingUtilities.invokeLater(r);
    }
    

    【讨论】:

    • 啊,我看错了;您的意思是要从某个 other 线程调用 someMethod() 并在其上休眠,例如Initial Thread.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多