【问题标题】:Calling event dispatch thread调用事件派发线程
【发布时间】:2013-04-26 00:21:28
【问题描述】:

我有一个扩展 JFrame 的主类。

我将面板添加到这个由 JTable 和其他 Swing 组件组成的框架实例中。

在“public static void main”这个主类中,我设置了swing事件调度线程。

我将面板添加到此实例框架,并启动:

this.setTitle("Test");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);

等等……

到这里一切都好。

现在,对于 JTable,它有一个监听器,当点击一行时,它会打开一个类 InfoDialog 的新实例。

在这个 InfoDialog 中,我照常添加 Swing 组件。

我在 JDialog 中有另一个调度线程,如下所示:

class InfoDialog  {
    JDialog jd;
    public void initGUI() {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
                 jd = new JDialog();
            jd.setModalityType(ModalityType.APPLICATION_MODAL);
            jd.setTitle("Buy");
            jd.setDefaultCloseOperation(jd.DISPOSE_ON_CLOSE);
            jd.pack();
            jd.setLocationRelativeTo(null);
    jd.setVisible(true);
    }});
   } 
}

放置事件调度线程解决了我遇到的错误(可能是因为它先前阻塞了当前线程),我的问题是,这是正确的方法吗?

感谢您的建议。

【问题讨论】:

  • 问:是什么错误导致您选择自己编写 .invokeLater()?问:认为您的方法可能存在什么问题?郑重声明:不,我看不出你的所作所为有什么问题。恕我直言...
  • 发生的事情是,当我单击行并设置 InfoDialog 的新实例时,我在此之后设置的属性和其他实例也与 InfoDialog 实例一起使用,这些实例仅在我关闭后才设置InfoDialog 实例。使用 InfoDialog 实例本身中的另一个事件调度线程,它会同时设置这些属性,否则当我尝试在 InfoDialog 的 UI 上执行操作时会引发错误,这些操作引用了其他不会设置的其他实例。希望这是有道理的。
  • 另外,似乎在对话框上设置了 ModalityType.APPLICATION_MODAL 会发生这种情况,我必须使用调度线程。
  • 如果modality type设置为null,它基本上可以在没有事件调度线程的情况下工作,但我不想要这种行为。
  • 感谢您的评论。

标签: java swing


【解决方案1】:

基本上,您应该只在事件调度线程的上下文中创建对话框(以及所有其他 UI 组件)并与之交互。

您可以(在某种程度上)通过从您的 main 方法调用 EventQueue.invokeLater 来确保这一点。这可确保大部分 UI 已在 EDT 的上下文中被调用。

public static void main(String args[]) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            //...Your UI code here...
        }
    });
}

假设您在所有其他时间都在 EDT 内应该是安全的。确保这一点应该是调用者的责任,而不是您的组件。我经常创建“安全”工厂方法,以便更轻松地构建一些设计和记录为线程安全的 UI 组件(例如进度指示器)。

查看Concurrency in SwingInitial Threads 了解更多详情。

【讨论】:

  • 我同意,我相信这正是我现在正在实施的方式。在主 GUI 的主类上调用 EventQueue.invokeLater,然后在 JDialog GUI 实例上调用 EventQueue.invokeLater。
  • 您不需要在对话框的构造函数中调用EventQueue.invokeLater。如果你这样做,那么对话框是在 EDT 之外构建的,这是不好的。在构建对话框之前,请确保您在 EDT 的上下文中,您可以使用EventQueue.isDispatchingThread() 来检查...
  • 但是我知道每个实例都不是主 EDT 的一部分,在这种情况下如何确保它是?通过参考?
  • 只有一个 EDT。如果EventQueue.isDispatchingThread() 返回 false,那么您的代码正在除 EDT 之外的线程中执行。你的组件代码不应该(除非你需要另外设计它)关心这个,它应该是调用者的责任来确保这一点。因此,在创建对话框之前,如果您认为自己可能不在 EDT 之外,请检查 EventQueue.isDispatchingThread()。如果是false,那么您应该使用EventQueue.invokeLater 与EDT 重新同步...
  • 嘿,我在Programmers Stack Exchange 上写了一个提到你的问题,摆动和线程安全。希望大家看看
【解决方案2】:

只有一个 AWT EDT。 (Applets 和 WebStart 中可以有多个,但实际上只有一个。)

你的invokeLater 发生的事情是一个事件被放置在EventQueue 上,然后通过initGUI 的调用者返回执行,先前排队的事件被调度,然后你的run 方法被执行。

您可能应该将调用移至initGUI() 的代码下方。

【讨论】:

  • 谢谢。经过数十小时的调试,我确实吸取了教训。
猜你喜欢
  • 2011-04-07
  • 1970-01-01
  • 2014-04-04
  • 2015-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多