3

我读过几本关于 Java 的书。在所有这些中,至少有一章教授 GUI 编程。在所有这些中,创建一个简单的表单应用程序都遵循以下逻辑:

MyFrame.java

public class MyFrame extends JFrame
{
    JButton button1;

    public MyFrame()
    {
        button1 = new JButton("Click here.");
    }
}

FrameTest.java:

public class FrameTest
{
    public static void main(String[] args)
    {
        MyFrame myFrame = new MyFrame();

        myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        myFrame.setSize(600, 600);
        myFrame.setVisible(true);
    }
}

基本上,只需将 JFrame 子类化以创建表单并将其他组件声明为实例变量并在构造函数中初始化这些组件。然后创建另一个测试类,在该类中实例化框架子类并调用它的一些方法使其可见。

但是在并发课程中,我了解到我们有一个主线程,它在我们创建的每个应用程序中运行 main()。据我所知,当我们使用 Swing 来创建 GUI 应用程序时,我们有另一个线程(Event Dispatcher Thread)。所以如果我没记错的话,在每个基于 Swing 的 GUI 应用程序中至少有两个线程。这使得每个 GUI 应用程序都是多线程的。在我读过的一些文章和教程中,它说 Swing 不支持多线程,因此所有 GUI 组件都应该只在 Event Dispatcher Thread 中创建和修改,否则可能会出现线程干扰和内存不一致错误。

即使在 Wikipedia ( http://en.wikipedia.org/wiki/Swing_%28Java%29 ) 中最简单的示例中,它也是通过 invokeLater 方法实现的。

那么哪一种才是真正的方法呢?我哪里错了?

4

2 回答 2

7

与任何 UI/Swing 组件的所有交互都必须在 EDT 的上下文中完成

启动应用程序时,您应确保在 EDT 中执行,然后再尝试创建任何 Swing 组件/与之交互。

简而言之,您应该使用类似...

EventQueue.invokeLater(new Runnable() {
    public void run() {
        // Now in the event dispatching thread
    }
});

如果您需要运行长时间运行的任务或执行任何阻塞任务,您应该在单独的线程中执行它。 SwingWorker在大多数情况下是一个不错的选择,因为它提供了一些简单的机制来将代码重新同步到事件调度线程。

通读一遍

所以,简短的回答是,是的,所有基于 Swing 的代码都应该从 EDT 的上下文中访问/修改/交互

于 2013-03-13T20:36:16.553 回答
3

所以如果我没记错的话,在每个基于 Swing 的 GUI 应用程序中至少有两个线程

是的。一个是主线程,另一个是 EDT(事件调度线程)。

这使得每个 GUI 应用程序都是多线程的。

是的。但在这种情况下,另一个线程不与 GUI 组件交互。

Swing 不支持多线程,因此所有 GUI 组件只能在 Event Dispatcher 线程中创建和修改,否则可能会出现线程干扰和内存不一致错误。

是的,绝对正确。这意味着一次只有一个线程应该与给定的 GUI 组件交互。
Swing 程序员处理以下类型的线程:

  • Initial threads,执行初始应用程序代码的线程。
  • 事件调度线程,所有事件处理代码都在其中执行。大多数与 Swing 框架交互的代码也必须在这个线程上执行。
  • 工作线程,也称为后台线程,执行耗时的后台任务。

程序员不需要提供显式创建这些线程的代码:它们由运行时或 Swing 框架提供。程序员的工作是利用这些线程来创建一个响应迅速、可维护的 Swing 程序。

于 2013-03-13T20:55:46.287 回答