14

こんにちは私はSwingを使ってJava1.6でGUIアプリケーションを書いています。

Swing guiの読み込み中と少し後に、gifアニメーションを表示するポップアップ画面があります。

ポップアップ画面はJDialogです。アニメーションは、次の方法でJdialogに追加されたJLabelに表示される必要があります。

ImageIcon myImgIcon = getMyImgIcon();
JLabel imageLbl = new JLabel(myImgIcon);
add(imageLbl, BorderLayout.CENTER); 

ここで重要なのは、GUIがロードされた後にのみアニメーションが表示されるということです。GUIがロードされている間(私のアプリケーションでは重い操作です)、EDTは非常にビジーで、アニメーションを実行できないと思います。

スレッドを使用してアニメーションGIF画像を表示するにはどうすればよいですかを参照してください。

さて、GUIを別のスレッド(EDTではない)にロードするのは間違っているので、問題を解決する方法がわかりません。

誰かアイデアがありますか?

4

4 に答える 4

9

いくつかの重いタスクの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を使用する必要があります。そして、すべてがあなたのケースに依存するので、私はこれ以上具体的なことを言うことはできません...

于 2012-09-24T15:43:25.037 に答える
3

おそらく、今後のイベントやコンポーネントに干渉することなく、アプリケーションの開始時に再生されるアニメーションを作成しようとしています。したがって、画面をスプラッシュしてみることをお勧めします。ここからそれについて読んでください:http://docs.oracle.com/javase/tutorial/uiswing/misc/splashscreen.html

上記のリンクでSplashScreenは、Frameクラスから派生したばかりのという名前のクラスの使用法を示しています。つまり、メカニズムは次のようになります。別のフレームを表示し(スプラッシュ画面、アニメーションはここに表示されます)、しばらくするとメインアプリケーションが起動します。

于 2012-09-24T13:48:02.417 に答える
2

'ImageIcon'クラスを使用すると、gifアニメーションを読み込むことができます。'getResource()'を使用して画像をロードします。これを行うために、私は通常、ファイルパスを渡すためにURLクラスを使用します。名前のURLが示すように、パスはリモートマシンで必要である必要はありません。

URL url = this.getClass().getResource(path);
Icon myImgIcon = new ImageIcon(url);
JLabel imageLbl = new JLabel(myImgIcon);
component.add(imageLbl, BorderLayout.CENTER);

pathは、クラスフォルダ内のgifのパスになります。

参照: http ://docs.oracle.com/javase/tutorial/uiswing/components/icon.html#getresource

于 2014-04-27T16:49:56.677 に答える
1

JFrameなどの内部で、これを使用します。

Icon imgIcon = new ImageIcon(this.getClass().getResource("ajax-loader.gif"));
JLabel label = new JLabel(imgIcon);
label.setBounds(669, 42, 45, 15); // You can use your own values
frame.getContentPane().add(label);

ソース:JavaSwingでアニメーションGIFを表示する方法

于 2019-04-04T15:26:49.763 に答える