Ответ 1
Вам просто нужно освободить поток EDT от некоторых тяжелых задач и выполнить их в отдельном потоке. В этом случае gif анимация будет работать вместе с другими запущенными процессами.
Вы также можете создать свой интерфейс приложения в отдельном потоке (да, да, не внутри EDT), но только до тех пор, пока вы его не отобразите. После этого вы должны внести все изменения в EDT, иначе вы можете столкнуться с множеством проблем.
Позже вы также можете загрузить больше элементов пользовательского интерфейса в отдельном потоке, просто убедитесь, что вы добавляете их в отображаемые фреймы/контейнеры внутри EDT - это самое главное.
Вот небольшой пример "тяжелой" загрузки интерфейса:
public static void main ( String[] args ) throws InvocationTargetException, InterruptedException
{
// Main window
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 );
}
} );
// Load dialog
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 );
}
} );
// Heavy task (takes approx. 10 seconds + some time on buttons creation)
for ( int i = 0; i < 100; i++ )
{
Thread.sleep ( 100 );
final JButton button = new JButton ( "Button" + i );
final int finalI = i;
// Updating panel and progress in EDT
SwingUtilities.invokeLater ( new Runnable ()
{
public void run ()
{
panel.add ( button );
button.revalidate ();
progressBar.setValue ( finalI );
}
} );
}
}
Как видите, все операции по обновлению интерфейса выполняются в EDT, все остальное выполняется внутри другого потока.
Также обратите внимание, что основной поток не является потоком EDT, поэтому мы можем сделать что-то тяжелое прямо сейчас.
В некоторых случаях нет необходимости отображать загруженные части интерфейса сразу, поэтому вы можете добавить их все вместе в конце "тяжелой" операции. Это сэкономит время загрузки и сделает код инициализации намного проще.
Краткое объяснение о EDT и что я сказал в ответе...
... это было то, что я нашел после трех лет работы под Swing L & F и множества приложений на базе Swing. Я копал много исходников Swing и нашел много интересных вещей, которые не очень известны.
Как вы знаете, вся идея единого потока для обновлений интерфейса (его EDT в Swing) заключается в том, чтобы хранить отдельные визуальные обновления каждого компонента (и его события) в очереди и выполнять их один за другим внутри этого потока. Это необходимо в основном для того, чтобы избежать проблем с рисованием, поскольку каждый компонент в одном кадре окрашивается в одно изображение, которое хранится в памяти. Порядок рисования там строгий, поэтому один компонент не будет перезаписывать другой на конечном изображении. Порядок рисования зависит от дерева компонентов, которое создается путем добавления некоторых компонентов или контейнеров в другой контейнер (это основная вещь, которую вы делаете при создании любого интерфейса приложения в 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 указала в документах, что даже создание компонентов Swing должно выполняться внутри EDT, чтобы избежать возможных проблем. Они могут появляться в некоторых особых случаях при создании сложных интерфейсов из-за событий, которые происходят во время создания компонентов.
В любом случае, я бы сказал, что в некоторых случаях вы можете создать свой интерфейс вне EDT, чтобы избежать зависания загрузчика/приложения. В других случаях, когда не имеет значения, зависло ли приложение на время создания интерфейса, следует использовать EDT. И я не могу сказать ничего более конкретного, так как все зависит от вашего случая...