5

私はJavaで一連の画像を次々に表示し、それぞれのフレームのサイズを調整するプログラムを作成しようとしています。JPanel を拡張して、次のような画像を表示しています。

public class ImagePanel extends JPanel{

String filename;
Image image;
boolean loaded = false;

ImagePanel(){}

ImagePanel(String filename){
    loadImage(filename);
}

public void paintComponent(Graphics g){
    super.paintComponent(g);
    if(image != null && loaded){
        g.drawImage(image, 0, 0, this);
    }else{
        g.drawString("Image read error", 10, getHeight() - 10);
    }
}

public void loadImage(String filename){
    loaded = false;         
    ImageIcon icon = new ImageIcon(filename);
    image = icon.getImage();
    int w = image.getWidth(this);
    int h = image.getHeight(this);
    if(w != -1 && w != 0 && h != -1 && h != 0){
        setPreferredSize(new Dimension(w, h));
        loaded = true;
    }else{
        setPreferredSize(new Dimension(300, 300));
    }
}

}

次に、イベント スレッドで主な作業を行っています。

        SwingUtilities.invokeLater(new Runnable(){

        @Override
        public void run(){
            createGUI();
        }
    });

createGUI() では、一連の画像を調べています。

        ImagePanel imgPan = new ImagePanel();
    add(imgPan);

    for(File file : files){
        if(file.isFile()){
            System.out.println(file.getAbsolutePath());

            imgPan.loadImage(file.getAbsolutePath());
            pack();

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
        }
    }

問題は、私のプログラムが適切にサイズ変更を行うため、画像は正しく読み込まれますが、何も表示されないことです。画像を1つだけ表示すると、最後の画像でも機能します。問題は、画像の描画が完了する前に Thread.sleep() が呼び出されることだと思います。

ImagePanel がペイントを終了し、その後待機を開始するのを待つにはどうすればよいですか? または、問題を解決する別の方法はありますか?

ありがとう!レオンティ

4

3 に答える 3

6

すべてのコードは、イベント ディスパッチ スレッドで実行されています。イベント ディスパッチ スレッドはすべてのユーザー インタラクション (入力 (イベント) と出力 (ペイント) の両方) を担当するため、これによりすべてのユーザー インタラクションが実質的にスリープ状態になります。

EDTの外で待機する必要があります。EDT の内外でイベントを実行する方法を知っておく必要があります。これを行うには、新しいRunnableを作成してから、呼び出しnew Thread(runnable)て EDT から実行するか、EDTSwingUtilities.invokeLater(runnable)で実行させます。Swing オブジェクトはスレッドセーフではないため、Swing コンポーネントとのやり取りはすべて EDT で行う必要があります。すべてのスリープ、待機、ファイル アクセス、ネットワーク アクセス、データベース アクセス、またはその他不確定な期間ブロックされる可能性のあるものはすべて、EDT から離れて実行する必要があります。

イベント ディスパッチ スレッドに関係するスタック オーバーフローについては、多くの質問があります。これらを確認して、さまざまな方法で実行しようとしていることを実行するための詳細情報とコード サンプルを見つけることをお勧めします。

于 2010-12-09T19:34:06.410 に答える
1

画像が読み込まれるたびに (つまり、Web ページのように) 画像を 1 つずつ表示したいようですね。それでよろしいですか? その場合、すべての画像が読み込まれるまで UI が更新されないため、現在のコードではその効果が得られません。これは、同じスレッドである EDT (イベント ディスパッチ スレッド) で画像を読み込んでいるためです。塗装をします。描画は「時間があるときに」行われます。この場合、すべての画像が読み込まれた後です。

あなたの問題を解決するには、次のようなSwingWorkerのサブクラスを作成することをお勧めします。

public class MyImageLoader extends SwingWorker<Void, String>
{
    // Is executed in background thread, EDT can meanwhile load and paint images
    @Override
    protected Void doInBackground() throws Exception
    {
        for(File file : files)
        {
             if(file.isFile()) // Maybe some more check to see if it's an image
             {
                 publish(file.getAbsolutePath());
                 Thread.sleep(500);
             }
        }
    }

    // Executed on EDT
    @Override
    protected void process(List<String> filePaths)
    {
        for(String path : filePaths)
        {
            // Load ImageIcon to UI
        }
    }
}
于 2010-12-09T19:50:45.373 に答える
1

スレッドをスリープ状態にする代わりに、タイマーを使用して次のイメージをイベントとして開始します。

于 2010-12-09T19:31:04.043 に答える