7

今天早些时候我试图看看我是否可以回答这个问题。我意识到我并不完全理解Event Dispatch ThreadEDT)。谷歌搜索既证实了这一点,又对此有所帮助,并澄清了我为什么不这样做。(也可能与理解有关。)

该代码设置了一个 GUI,然后(如前面的问题)更新一个文本字段,直到取消设置一个标志。

我有几个问题/要求。

  • 请解释为什么如果两个调用(toswingInitdoIt)都在invokeLater块之外(如图所示),下面的代码运行良好,因为这两个调用都会影响或查询 GUI,但都没有在 EDT 上执行(是吗?)。这不是招致失败吗?

  • 如果调用swingInit是 inside 和doItoutside ,代码也会运行invokeLater。所以swingInit在 EDT 上执行,但不应该在doItEDT 上执行不是问题吗?(我很惊讶这行得通。我应该是吗?)

  • 我想我明白为什么如果doIt在里面invokeLater不管它在哪里都会挂起swingInit:目的invokeLater只是初始化GUI(对吗?)。

  • 应该doIt只在 EDT 上启动(可能从发生的事件开始),但肯定不能invokeLater块内启动?

(EDT 概念的历史很有趣。并非总是如此。请参阅上面的“为什么我不理解它”的链接。)

import static java.awt.EventQueue.invokeLater;
import java.awt.event.*;
import javax.swing.*;

public class Whatever 
{
  static boolean flag = true;
  static JTextField tf = new JTextField("Hi",20);
  static JPanel p = new JPanel();
  static JFrame f = new JFrame();
  static JButton b = new JButton("End");

  public static void main(String[] args)
  {
    swingInit();

    invokeLater
    (
      new Runnable()
      {
        @Override
        public void run() 
        {
    //    swingInit();
    //    doIt();
        }
      }
    ); 
   doIt();      
  } 

  static void swingInit()
  {
     b.addMouseListener
    (
        new MouseAdapter()
        {
          @Override
          public void mouseClicked(MouseEvent e)
          {
            flag = false;
            JOptionPane.showMessageDialog(null,"Clicked... exiting");
            System.exit(0);
          }
        }
    );

    p.add(tf);
    p.add(b);
    f.add(p);
    f.setVisible(true);
    f.pack();
    f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
  }

  static String getInfo(){
    return "Hello... " + Math.random();
  }

  static void doIt(){
    while(flag)     
      tf.setText(getInfo());
  }; 
}
4

2 回答 2

3

考虑每个要点:

  • The code is launched on the Main thread - the EDT is run in parallel. swingInit returns after constructing the UI which is then under control of the EDT, allowing dotIt to do its thing in parallel on the main thread

  • Similar situation as above, but here you are guaranteeing construction of the UI on the EDT (as recommended by Oracle).

  • A long running task is placed onto the EDT, preventing it from showing (if placed before swingIt) or painting and interaction (if placed after). the purpose of invokeLater is ONLY to initialize the GUI The purpose is to place non-thread safe Swing calls onto the EDT. If within the main method, I would recommend using SwingUtilities.invokeAndWait

  • If you wish to update the UI like this, consider doing so with a SwingTimer.

Running EDT specific, non-thread safe code outside the EDT doesn't guarantee failure, but it does invite failure (via conflicts when two (or more) threads attempt to update data at the same time).

I once spent hours tracking down a mysterious NullPointerException, only to realize it was a LookAndFeel issue whose calls were not on the EDT. Lesson learned.

于 2015-05-08T19:46:20.937 回答
2
static void doIt(){
  while(flag)     
    tf.setText(getInfo());
}; 

内部的繁忙循环doIt占用了 GUI 线程(在该循环中旋转),这将导致 GUI 挂起。

您实际上并没有解释“运行良好”的含义,但我假设这就是您所看到的问题。

您可能希望使用Swing Timer来执行类似于您在循环中执行的操作。

于 2015-05-08T19:35:27.873 回答