忽略事件分派线程如何让这个程序工作?

How does ignoring the event dispatch thread allow this program to work?

因为我试图看看我是否可以回答 this question earlier today. I realized that I don't fully understand the Event Dispatch Thread (EDT). Googling both confirmed and helped with that and clarified why I don't. (This 可能也与理解有关。)

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

我有几个questions/requests.

(EDT 概念的历史很有趣。并非总是如此。请参阅上面的 link 以 "why I don't" 理解它。)

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());
  }; 
}
static void doIt(){
  while(flag)     
    tf.setText(getInfo());
}; 

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

您实际上并没有解释 "runs fine" 的意思,但我假设这就是您遇到的问题。

您可能想使用 Swing Timer 来做一些类似于您在循环中所做的事情。

记下你的每一个要点:

  • 代码在主线程上启动 - EDT 是 运行 并行的。 swingInit returns 在构建 UI 之后 控制 EDT,允许 dotIt 在主线程上并行执行其操作

  • 与上述类似的情况,但这里您保证在 EDT 上构建 UI(根据 Oracle 的建议)。

  • 一个长 运行ning 任务被放置到 EDT 上,阻止它显示(如果放置在 swingIt 之前)或绘画和交互(如果放置在之后)。 the purpose of invokeLater is ONLY to initialize the GUI 目的是将非线程安全的 Swing 调用置于 EDT 上。如果在主要方法中,我建议使用 SwingUtilities.invokeAndWait

  • 如果您希望像这样更新 UI,请考虑使用 SwingTimer

运行 EDT 特定的、EDT 之外的非线程安全代码不保证失败,但确实邀请失败(当两个(或更多)线程尝试同时更新数据时发生冲突)。

我曾经花了几个小时追踪一个神秘的 NullPointerException,才意识到这是一个 LookAndFeel 问题,其调用不在 EDT 上。学过的知识。