【问题标题】:Updating swing components within edt在 edt 中更新 swing 组件
【发布时间】:2015-04-23 04:47:09
【问题描述】:

如果我理解正确,那么当我创建 GUI 摆动组件时,例如我有这个:

public class frameExample extends JFrame{
    public frameExample(){
    //Here adding bunch if components
    setVisible(true);
    }
}

只要我不调用 setVisible 方法,组件就会从创建实例的线程中生成。所以如果在一个我有我的主要方法的类中写:

JFrame test=new frameExample();

然后我就退出了

Thread.currentThread.getName(); 

在 setVisible 之前的 frameExample 的构造函数中,我应该得到:main。

之后,创建和维护 swing 元素的职责被传递给 event-dispatch-thread,因为它不是线程安全的,所以每个组件的添加/删除/修改都应该在 EDT 线程中完成。

所以我应该把我的 setVisible 作为我构造函数的最后一行代码,或者单独调用它。

据我了解,所有事件侦听都通过 EDT。因此,如果我在例如 actionPerformed 方法中创建一个新组件,它应该可以正常工作。

另外,如果我将一个可运行实例传递给 invokeLater 或 invokeAndWait,那么所有 run() 方法都将由 EDT 完成。

所以这就是我感到困惑的原因。

我编写了这段代码:

public class GUI extends JFrame {


JButton btn = new JButton("Change");
JMenuBar m = new JMenuBar();

public GUI() {
    super("Test");
    setSize(400, 400);
    setDefaultCloseOperation(EXIT_ON_CLOSE);

    m.add(new JMenu("menu"));
    add(m, BorderLayout.NORTH);

    add(btn, BorderLayout.SOUTH);
    System.out.println("Current thread: before setVisible "+Thread.currentThread().getName());

    setVisible(true);

    System.out.println("Current thread: after setVisible "+Thread.currentThread().getName());
    btn.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {

            add(new JButton("testbtn1"), BorderLayout.EAST);
            add(new JButton("testbtn2"));
            System.out.println("Current thread: "+Thread.currentThread().getName());


            new Thread(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    for (int i = 0; i < 1E8; i++) {
                        Math.sin(5.0);
                    }
                    System.out.println("Current thread: "+Thread.currentThread().getName());
                }
            }).start();

        }
    });
}

}

所以在我的匿名类中,我在 EDT 中添加了两个按钮,但是在我调整它的大小之后,组件并没有添加到我的框架中(这会迫使 edt 更新其组件???原因是什么?这个?)。

所以即使在 edt 中我也没有得到我的新组件,但是当我在 edt 之外创建一个随机线程并使其更改某些 gui 元素属性(例如 setText)时,在 edt 之外就可以正常工作。

所以我的第一个问题是:为什么我的组件没有在 edt 中更新以及为什么它们在调整大小后可见

第二个:为什么我可以对 edt 之外的 swing 组件进行更改并且一切正常?这是否只是随机线程行为,例如在没有同步块的情况下一切正常,但是当您重新运行程序时,它最终会因为缺乏同步而崩溃。

【问题讨论】:

    标签: java multithreading swing actionlistener event-dispatch-thread


    【解决方案1】:

    只要我不调用 setVisible 方法,组件就会由创建实例的线程制成

    错了。只要您不专门创建新的Thread 或使用实用方法(例如SwingUtilities#invoke... 方法),就会在当前Thread 上调用每个调用,包括setVisible 调用。

    您似乎认为使 Swing 组件可见以某种方式使您的代码切换线程。不,Swing 组件的绘制将在 EDT 上进行。正如您正确指出的那样,Swing 不是线程安全的。 这就是为什么您也应该在 EDT 上创建组件,而不是在另一个线程上。它可能在大多数情况下都可以正常工作,但最终你会偶然发现奇怪的错误。

    据我了解,所有事件侦听都通过 EDT。因此,如果我在例如 actionPerformed 方法中创建一个新组件,它应该可以正常工作。

    另外,如果我将一个可运行实例传递给 invokeLater 或 invokeAndWait,那么所有 run() 方法都将由 EDT 完成。

    正确。

    所以在我的 anonim 类中,我在 EDT 中添加了两个按钮,但是在我调整它的大小之后组件并没有添加到我的框架中

    Container 添加组件需要您重新验证布局(请参阅Container#add 方法的javadoc)。只需拨打电话

    revalidate();
    repaint();
    

    添加按钮后,它将按预期工作。手动调整框架大小与您已经注意到的效果相同。

    所以即使在 edt 中我也没有得到我的新组件,但是当我在 edt 之外创建一个随机线程并使其更改某些 gui 元素属性(例如 setText)时,在 edt 之外就可以正常工作。

    如前所述,它可能在大多数情况下都有效,但不能保证它在 100% 的时间内都有效。上面解释了添加组件没有按预期工作的原因,与线程问题无关。

    【讨论】:

    • "每个调用都是在当前线程上调用的,包括 setVisible 调用。看起来你认为让 Swing 组件可见会以某种方式使你的代码切换线程。" 不,他不这么认为。他清楚地知道 setVisibel(true) 启动了 EDT。
    猜你喜欢
    • 2013-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多