いくつかの重いタスクのEDTスレッドを解放し、それらを別のスレッドで実行する必要があります。その場合、gifアニメーションは実行中の他のプロセスと連携して機能します。
また、アプリケーションインターフェイスを別のスレッドで作成することもできます(はい、EDT内ではありません)が、表示するまでの間だけです。その後、EDT内ですべての変更を行う必要があります。そうしないと、多くの問題が発生する可能性があります。
後で別のスレッドにさらに多くのUI要素をロードすることもできます。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ベースのアプリケーションで3年間働いた後に見つけたものでした。私はたくさんのSwingソースを掘り起こし、広く知られていない興味深いものをたくさん見つけました。
ご存知のように、インターフェイス更新(SwingでのEDT)の単一スレッドの全体的な考え方は、個々のコンポーネントの視覚的更新(およびそのイベント)をキューに保持し、そのスレッド内で1つずつ実行することです。これは主に、単一フレーム内のすべてのコンポーネントがメモリに保持されている単一の画像にペイントされるため、ペイントの問題を回避するために必要です。そこではペイントの順序が厳密であるため、最終的な画像で1つのコンポーネントが別のコンポーネントを上書きすることはありません。ペイントの順序は、別のコンテナ内にいくつかのコンポーネントまたはコンテナを追加することによって作成されるコンポーネントツリーによって異なります(これは、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を使用する必要があります。そして、すべてがあなたのケースに依存するので、私はこれ以上具体的なことを言うことはできません...