在程序启动时操作Swing组件的正确方法是什么?

时间:2009-10-15 15:07:35

标签: java swing multithreading

我正在使用NetBeans在Swing中创建一个应用程序。我想能够在窗口可见之后操作一些组件(仅一次),例如更新进度条。为此,我有应用程序的主类,名为MainWindow:

public class MainWindow extends JFrame
{

public MainWindow()
{
    initComponents(); // NetBeans GUI builder-generated function for setting
                      // up the window components

}

public void Init()
{
     loadLabel.setText("Loading....");
     loadProgressBar.setValue(20);
     doSomething();
     loadProgressBar.setValue(40);
     doSomething();
     loadProgressBar.setValue(80);
     doSomething();
     loadProgressBar.setValue(100);

     loadLabel.setVisible(false);
     loadProgressBar.setVisible(false);
}

/* .... */

public static void main(String args[]) 
{
    java.awt.EventQueue.invokeLater(new Runnable() 
    {
        public void run() 
        {
            mainHandle = new MainWindow();
            mainHandle.setVisible(true);
            mainHandle.Init();
        }
    });
}

}

问题是无法观察到Init()函数中更新进度条(或操作任何其他GUI组件)的语句的影响。如果从main()内部调用Init()函数,如上所示,窗口出现,但是为空,Init()函数执行并返回,只有在窗口绘制其内容之后,但Init()所做的任何更改都是因为窗口是空的而且一直无效,所以不可见。我也尝试从windowOpened()AWT事件中调用init,该事件在窗口完全绘制后执行,但是令人惊讶地将任何用于操作组件的语句放在那里似乎没有效果,或者说它们被放入队列中,并在有些点是连续的,所以只能观察到最后一个(隐藏元素)的影响。我设法让它工作的唯一方法是删除整个invokeLater(新的Runnable()...)mantra并将新的MainWindow(),setVisible(),Init()序列直接放在main()中,我猜是非常丑陋的,打破了以线程方式运行的gui的概念。这样做的正确方法是什么?当gui准备好被操作时,我在哪里首先执行代码,执行一次语句并将控制权返回给主事件循环?

我想目前这是以这种方式工作的,当Init()函数运行时,gui组件上的任何操作都被挂起(绘图线程不是独立的,等待Init()完成在执行操作之前)。也许我应该让Init()成为一个新的线程...只有怎么样和什么样的?

感谢。

2 个答案:

答案 0 :(得分:1)

您可以将EventQueue.invokeLater()更改为invokeAndWait(),并将调用init()移至第二个EventQueue.invokeLater()调用。

如果(看起来是这样)doSomething()需要花费大量时间,最好将Init代码移动到SwingWorker的主体中。这可以从MainWindow()构造函数执行,也可以在main中调用setVisible()之后执行,并且是具有响应GUI的惯用方法(如果用户感到厌倦等待并想要退出)并显示一些可见的进展迹象。

有关如何更新doSomething()调用之间的进度条的详细信息,请参阅processpublish方法。

您可能还想查看ProgressMonitors以获取另一个可以处理对话框等的替代方案。

答案 1 :(得分:1)

你可以做几件事:

  1. 对于Windows(例如JFrameJDialog),您可以附加WindowListener并在windowOpened方法中进行操作。
  2. 覆盖addNotify方法并在那里进行控制操作。
  3. 附加HierarchyListener并在组件的可显示性发生变化时进行操作。
  4. 始终确保您在EDT上进行组件操作。使用SwingUtilities.invokeLater进行简单的UI更新,或SwingWorker进行长时间运行的任务