为什么actionPerform()在Event Dispatch Thread中运行但是componentAdded()不是?

时间:2012-11-08 08:59:33

标签: java multithreading swing event-dispatch-thread

我的Ex1如下:

main(String args[]) {
    JFrame frame = new JFrame("Title");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JButton button = new JButton("Press Here");
    ContainerListener container = new ContainerAdapter() {
      public void componentAdded(final ContainerEvent e) {
          System.out.println("On the event thread? : " +
                  EventQueue.isDispatchThread());
      }
    };
    frame.getContentPane().addContainerListener(container);
    frame.add(button, BorderLayout.CENTER);
    frame.setSize(200, 200);
    System.out.println("I'm about to be realized: " +
      EventQueue.isDispatchThread());
    frame.setVisible(true);
  }

我的结果是:在事件线程上? :FALSE |我即将意识到:虚假

其他Ex2:

public class GridBagLayoutTester
    extends JPanel implements ActionListener{   
public GridBagLayoutTester() {
    setLayout(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();

    JButton button = new JButton("Testing");
    // do something...
    button.addActionListener(this);
    add(button, gbc);
}

public void actionPerformed(ActionEvent e) {
    System.out.println("On the event thread? : " +
                  EventQueue.isDispatchThread());
}

public static void main(String[] args) {
    JFrame frame = new JFrame("GridBagLayoutDemo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    
    Container contentPane = frame.getContentPane();
    contentPane.setLayout(new BorderLayout());
    contentPane.add(new GridBagLayoutTester(), BorderLayout.CENTER);
    frame.setSize(800, 600);
    frame.pack();
    frame.setVisible(true);
    System.out.println("I'm about to be realized: " +
      EventQueue.isDispatchThread());
}   

}

结果是:我即将意识到:假|在事件线程? :TRUE

我的问题是为什么Ex1- componentAdded()在初始线程中运行,但Ex2- actionPerformed()在EDT中运行?

2 个答案:

答案 0 :(得分:3)

关于Java中GUI应用程序的几个事实:

- Java GUI 应用程序中,main()方法短命在安排GUI构建后Event Dispatcher Thread(EDT)退出

- 因此EDT's 负责处理GUI

现在来到您的代码:

- 初始线程是main()线程,EDT GUI线程

- 在EX1中,您强制GUI在main()线程上运行,这是一种错误的方式,在使用GridBagLayoutTester的EX2中扩展JPanel main()线程通过将GUI的工作委派给EDT 获得早期机会。

应该使用

- main()方法来执行进一步处理GUI的EventQueue.invokeLater()方法,这将帮助UI响应并避免处理任何非UI工作。

- 此外,Java拥有SwingUtilities类,可以在UINon-UI工作UI之间实现良好的同步分别是1}}和Non-UI线程。

例如:正确的做法.......

public class Test extends JFrame{

   public Test(){

       this.setSize(300,300);
       this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }


  public static void main(String[] args){


       EventQueue.invokeLater(new Runnable(){

              public void run(){

                   new Test().setVisible(true);

                }


           });

   }


}

答案 1 :(得分:2)

main方法的第一行创建了一个JFrame类型的新对象。这个创建启动一个新线程(实际上它启动了多个线程) - 一个等待事件队列项的新线程。例如,这可以是鼠标点击。 回答你的问题:主线程 - 真正称为“主” - 正在调用主方法的10行代码。这应该在几毫秒内完成。之后主线程消失了,不再存在了。 但正如我之前所说,AWT / Swing库在内部创建了一个(是的,更多)线程,它基本上是一个无限循环检查用户输入。并且从该线程调用actionPerformed方法。

我的建议:

  • 在main方法的第一行创建一个断点。

  • 调试程序。

  • 当调试器在第一行停止时(在创建JFrame之前)转到命令行并启动jconsole

  • 转到标签主题

  • 通知主题“主要”

  • 执行单行(新JFrame)

  • 注意线程“main”和线程共存“AWT - *”

  • 按调试器播放,“主”将消失,但AWT将持续