14

我有几个关于 Swing 和使用 EDT 进行 GUI 更新的问题。我刚开始阅读这些东西,所以我是这个领域的初学者:

  1. 在 EDT 上运行需要哪些操作?如果他们不这样做,是否只是引发了一个异常?
  2. 是否有任何特定时间我们实际上自动在 EDT 上?
  3. 如果我们安排一个任务,SwingUtilities.invokeLater我们将它排入当前的 GUI 更新任务队列(EDT),对吗?
  4. 对上面队列的访问我猜是同步的,或者使用了一些并发集合,但是如果我从两个后台线程调度两个GUI更新任务,就不可能说哪个会先添加?例如,如果线程 1 FIRST 提交了将 JLable 的文本设置为“是”的任务,然后不久之后,第二个线程出现并提交了将该值设置为“否”的任务,我们是否保证结果将是“是”,还是仅仅是操作系统如何安排这些事情的问题?
  5. SwingWorker 究竟如何确保该done()方法在 EDT 上运行?它设置以下代码:

      future = new FutureTask<T>(callable) {
                   @Override
                   protected void done() {
                       doneEDT();
                       setState(StateValue.DONE);
                   }
               };
    

所以我想知道 FutureTask 是否以某种方式确保invokeLater被调用?

感谢您的所有回答。

4

4 回答 4

18
  1. 一个好的规则是所有操作(访问/更新/...)都应该在 EDT 上进行。javadoc 中提到了一些例外(某些类的某些方法),但它们很难记住,因此更容易坚持“在 EDT 上做所有事情”的方法。不会引发异常(幸运的是,JavaFX 修复了这个缺点)。您可以使用自定义RepaintManager来检测大多数这些违规行为:请参阅这篇文章

  2. 用户触发的一切都在 EDT 上处理。例如,如果用户单击一个按钮,则在 EDT 上将调用actionPerformed相应的Action或。ActionListener

  3. 正确的

  4. 您首先安排的事情将首先执行。该invokeLater调用只是Runnable在队列末尾添加 。invokeLater稍后使用第二次将Runnable在先前安排的之后添加这个新的Runnable

  5. 看看代码doneEDT

     private void doneEDT() {
         Runnable doDone = 
             new Runnable() {
                 public void run() {
                     done();
                 }
             };
         if (SwingUtilities.isEventDispatchThread()) {
             doDone.run();
         } else {
             doSubmit.add(doDone);
         }
     }
    
于 2012-08-06T09:14:21.043 回答
8
  1. 基本上,每次使用 Swing 组件或 Swing 组件的模型时,都必须在 EDT 中完成。如果您不这样做,则不会引发任何异常。它可以工作,但也不能工作,行为不稳定,数据损坏等。
  2. 在 EDT 中调用每个 Swing 事件侦听器。基本上,除了 main 方法,Swing 应用程序的每一行代码都默认在 EDT 中执行,除非您明确启动线程、使用 SwingWorker 或类似的东西。
  3. 是的。
  4. 提交给 SwingUtilities.invokeLater() 的任务按照它们提交的顺序执行。
  5. 在内部,它使用 SwingUtilities.invokeLater() 或类似方法。FutureTask 与 Swing 没有任何关系。SwingWorker 确保其 done 方法在 EDT 中执行。该doneEDT()方法有以下注释:Invokes done on the EDT
于 2012-08-06T09:12:36.833 回答
0

SwingWorker 确保 done() 方法通过以下代码在 EDT 上运行:

    Runnable doDone =
        new Runnable() {
            public void run() {
                done();
            }
        };
    if (SwingUtilities.isEventDispatchThread()) {
        doDone.run();
    } else {
        doSubmit.add(doDone);
    }

实际上,它将 doDone 变量添加到 AccumulativeRunnable doSubmit 中,

查看 AccumulativeRunnable.java 的源代码,您会发现有以下代码

受保护的无效提交(){

SwingUtilities.invokeLater(this);

}

这就是为什么 swingworker 确保方法 done() 在 EDT 上运行

于 2016-01-21T02:47:43.380 回答
-1

1.在Java GUI应用程序中,main()方法寿命不长,在调度GUI构建后 Event Dispatcher Threadmain() 方法退出......现在它的EDT负责处理GUI。

2.所以我们不需要在 EDT 上启动我们的应用程序,它会自动完成。

3始终保持 UI 在 UI 线程上工作,Non-UI 在 Non-UI 线程上工作。

因此,请始终保留您的 EDT 线程,这是仅用于 GUI 工作的 GUI 线程。

例如:

public static void main(String[] args){
    EventQueue.invokeLater(new Runnable(){
          public void run(){    
            myframe.setVisible(true);
         }
     }
}

4.创建一个单独的非 UI 线程来处理那个耗时的方法。

5.你可以简单地使用Java中专门引入的Thread或使用来同步UI和Non-UI线程。SwingWorker

6. SwingWorker 不保证 done() 方法在 EDT 上运行,而是将其输出同步到 EDT 线程,即 GUI 线程。

于 2012-08-06T09:07:39.463 回答