我正在使用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()成为一个新的线程...只有怎么样和什么样的?
感谢。
答案 0 :(得分:1)
您可以将EventQueue.invokeLater()更改为invokeAndWait(),并将调用init()移至第二个EventQueue.invokeLater()调用。
如果(看起来是这样)doSomething()需要花费大量时间,最好将Init代码移动到SwingWorker的主体中。这可以从MainWindow()构造函数执行,也可以在main中调用setVisible()之后执行,并且是具有响应GUI的惯用方法(如果用户感到厌倦等待并想要退出)并显示一些可见的进展迹象。
有关如何更新doSomething()调用之间的进度条的详细信息,请参阅process和publish方法。
您可能还想查看ProgressMonitors以获取另一个可以处理对话框等的替代方案。
答案 1 :(得分:1)
你可以做几件事:
JFrame
或JDialog
),您可以附加WindowListener并在windowOpened方法中进行操作。addNotify
方法并在那里进行控制操作。HierarchyListener
并在组件的可显示性发生变化时进行操作。始终确保您在EDT上进行组件操作。使用SwingUtilities.invokeLater
进行简单的UI更新,或SwingWorker
进行长时间运行的任务