您只需将一些重要的任务从EDT线程中解放出来,并在另一个线程中完成它们。这样,gif动画将与其他正在运行的进程一起工作。
您还可以在单独的线程中创建应用程序界面(是的,不在EDT内),但仅限于显示界面之前。之后,您应该在EDT内进行所有更改,否则可能会遇到许多问题。
您还可以稍后在单独的线程中加载更多UI元素,只需确保将它们添加到EDT内显示的帧/容器中即可,这是最重要的事情。
以下是一个小的“重型”界面加载示例:
public static void main ( String[] args ) throws InvocationTargetException, InterruptedException
{
final JFrame frame = new JFrame ();
final JPanel panel = new JPanel ( new FlowLayout ( FlowLayout.LEFT, 5, 5 ) )
{
public Dimension getPreferredSize ()
{
Dimension ps = super.getPreferredSize ();
ps.width = 0;
return ps;
}
};
frame.add ( new JScrollPane ( panel ) );
frame.setSize ( 600, 500 );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setLocationRelativeTo ( null );
SwingUtilities.invokeAndWait ( new Runnable ()
{
public void run ()
{
frame.setVisible ( true );
}
} );
final JDialog load = new JDialog ( frame );
JPanel panel2 = new JPanel ( new BorderLayout () );
panel2.setBorder ( BorderFactory.createEmptyBorder ( 15, 15, 15, 15 ) );
load.add ( panel2 );
final JProgressBar progressBar = new JProgressBar ( 0, 100 );
panel2.add ( progressBar );
load.setModal ( false );
load.pack ();
load.setLocationRelativeTo ( frame );
SwingUtilities.invokeAndWait ( new Runnable ()
{
public void run ()
{
load.setVisible ( true );
}
} );
for ( int i = 0; i < 100; i++ )
{
Thread.sleep ( 100 );
final JButton button = new JButton ( "Button" + i );
final int finalI = i;
SwingUtilities.invokeLater ( new Runnable ()
{
public void run ()
{
panel.add ( button );
button.revalidate ();
progressBar.setValue ( finalI );
}
} );
}
}
如您所见,所有界面更新操作均在EDT中完成,其他所有操作都在另一个线程中运行。
同时请注意,主线程不是EDT线程,因此我们可以立即在那里执行一些繁重的操作。
在某些情况下,无需立即显示加载的界面部分,因此您可以将它们全部添加到“繁重”操作的末尾。这将节省一些加载时间,并使初始化代码更加简单。
关于EDT的简要说明和我在答案中所说的...
...这是我在使用Swing L&F和大量基于Swing的应用程序工作三年后发现的内容。我挖掘了许多Swing源代码,并发现了许多有趣的事情,这些事情并不广为人知。
就像您所知道的-单个线程用于界面更新(在Swing中是EDT)的整个想法是为了让每个单独的组件可视化更新(及其事件)都排队,然后在该线程内一次执行它们。这主要是为防止绘画问题,因为框架内的每个组件都绘制到保留在内存中的单个图像上。绘画顺序是严格的,因此一个组件不会覆盖另一个组件在最终图像上的位置。绘画顺序取决于添加某些组件或容器到另一个容器中创建的组件树(这是您在使用Swing创建任何应用程序界面时执行的基本操作)。
总之,您必须将所有可视化更新(可能导致它们的方法/操作)保留在EDT中。任何其他操作可能在EDT之外完成-例如,您可以在EDT之外准备应用程序界面(除非您在已经可见的容器内添加/删除/移动组件)。
尽管如此,在极其罕见的情况下可能会出现一些内部问题。很久以前曾进行过有关该问题的讨论:
http://www.velocityreviews.com/forums/t707173-why-does-jdk-1-6-recommend-creating-swing-components-on-the-edt.html
简而言之:自从第6个JDK版本以来,Sun在文档中指出,甚至应该在EDT中创建Swing组件,以避免可能的问题。由于在创建组件时发生事件,这些问题可能出现在具有繁重接口创建的特定情况中。
无论如何,我认为在某些情况下,您可以在EDT之外创建界面以避免加载器/应用程序被卡死。在其他情况下,当无论应用程序是否卡死都不重要时,您应该使用EDT。由于一切都取决于您的情况,因此我无法提供更具体的信息...