7

画像ファイルのサムネイルビューを使用して作成したかったので、JFileChooserFileViewをサブクラス化し、作成するメソッドでImageIcon、サムネイル画像が表示されるようにスケーリングを行いました。

ただし、全体的な効果として、filechooserウィジェットがディレクトリを開いてサムネイルを表示するまでに時間がかかることがあります。以下のcreateImageIcon()では、新しいImageIcon()を2回呼び出す必要があります。コンストラクター引数。これがウィジェットの速度を低下させるものだと思います。

より効率的な代替案はありますか?提案/ポインタは大歓迎です。

ありがとう、マーク

public static void main(String[] args) { 
    JFileChooser chooser=new JFileChooser();
    ThumbNailView thumbView=new ThumbNailView();
    chooser.setFileView(thumbView);
  }

class ThumbNailView extends FileView{
 public Icon getIcon(File f){
  Icon icon=null;
  if(isImageFile(f.getPath())){
   icon=createImageIcon(f.getPath(),null);
  }
  return icon;
 }
 private ImageIcon createImageIcon(String path,String description) {
  if (path != null) {
   ImageIcon icon=new ImageIcon(path);
   Image img = icon.getImage() ; 
   Image newimg = img.getScaledInstance( 16, 16,  java.awt.Image.SCALE_SMOOTH ) ;
   return new ImageIcon(newimg);
  } else {
   System.err.println("Couldn't find file: " + path);
   return null;
   }
}

private boolean isImageFile(String filename){
    //return true if this is image
}
4

3 に答える 3

10

Windows でネイティブのルック アンド フィールを使用しているにもかかわらず、実際にはファイル チューザーにサムネイル ビューがないことに驚きました。私はあなたの例を試してみましたが、あなたは正しい方向に進んでいますが、大きな画像がたくさんあるフォルダーではどれだけ遅いかがわかります。もちろん、オーバーヘッドは、ファイルの内容を読み取ってイメージを解釈するときの I/O によるものであり、これは避けられません。

さらに悪いことに、ファイル リストが表示される前、アイコンの上にマウスを置いたとき、および選択が変更されたときに、 が頻繁に呼び出さFileView.getIcon(File)れることがわかりました。画像を読み込んだ後に画像をキャッシュしないと、無意味に画像を常に再読み込みすることになります。

明らかな解決策は、すべての画像の読み込みを別のスレッドまたはスレッド プールにプッシュし、スケールダウンした結果を一時キャッシュに入れて、再度取得できるようにすることです。

私はImageと をImageIconいろいろいじり、 をImageIcon呼び出すことでいつでも のイメージを変更できることを発見しましたsetImage(Image)。これが私たちにとって何を意味するかというとgetIcon(File)、空白またはデフォルトのアイコンをすぐに返すことができますが、それへの参照を保持し、バックグラウンドで画像をロードし、後で完了時にアイコンの画像を設定するワーカー スレッドに渡します。 (唯一の問題は、変更を確認するために呼び出す必要があることですrepaint())。

この例では、ExecutorServiceキャッシュされたスレッド プール (すべての画像を取得する最速の方法ですが、多くの I/O を使用します) を使用して画像の読み込みタスクを処理しています。また、キャッシュとしてa を使用しWeakHashMapて、キャッシュされたアイコンが必要な間だけ保持されるようにします。別の種類のマップを使用することもできますが、メモリ不足を避けるために保持するアイコンの数を管理する必要があります。

package guitest;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Pattern;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.filechooser.FileView;

public class ThumbnailFileChooser extends JFileChooser {

    /** All preview icons will be this width and height */
    private static final int ICON_SIZE = 16;

    /** This blank icon will be used while previews are loading */
    private static final Image LOADING_IMAGE = new BufferedImage(ICON_SIZE, ICON_SIZE, BufferedImage.TYPE_INT_ARGB);

    /** Edit this to determine what file types will be previewed. */
    private final Pattern imageFilePattern = Pattern.compile(".+?\\.(png|jpe?g|gif|tiff?)$", Pattern.CASE_INSENSITIVE);

    /** Use a weak hash map to cache images until the next garbage collection (saves memory) */
    private final Map imageCache = new WeakHashMap();

    public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        JFileChooser chooser = new ThumbnailFileChooser();
        chooser.showOpenDialog(null);
        System.exit(1);
    }

    public ThumbnailFileChooser() {
        super();
    }

    // --- Override the other constructors as needed ---

    {
        // This initializer block is always executed after any constructor call.
        setFileView(new ThumbnailView());
    }

    private class ThumbnailView extends FileView {
        /** This thread pool is where the thumnnail icon loaders run */
        private final ExecutorService executor = Executors.newCachedThreadPool();

        public Icon getIcon(File file) {
            if (!imageFilePattern.matcher(file.getName()).matches()) {
                return null;
            }

            // Our cache makes browsing back and forth lightning-fast! :D
            synchronized (imageCache) {
                ImageIcon icon = imageCache.get(file);

                if (icon == null) {
                    // Create a new icon with the default image
                    icon = new ImageIcon(LOADING_IMAGE);

                    // Add to the cache
                    imageCache.put(file, icon);

                    // Submit a new task to load the image and update the icon
                    executor.submit(new ThumbnailIconLoader(icon, file));
                }

                return icon;
            }
        }
    }

    private class ThumbnailIconLoader implements Runnable {
        private final ImageIcon icon;
        private final File file;

        public ThumbnailIconLoader(ImageIcon i, File f) {
            icon = i;
            file = f;
        }

        public void run() {
            System.out.println("Loading image: " + file);

            // Load and scale the image down, then replace the icon's old image with the new one.
            ImageIcon newIcon = new ImageIcon(file.getAbsolutePath());
            Image img = newIcon.getImage().getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_SMOOTH);
            icon.setImage(img);

            // Repaint the dialog so we see the new icon.
            SwingUtilities.invokeLater(new Runnable() {public void run() {repaint();}});
        }
    }

}

既知の問題点:

1) スケーリング時に画像の縦横比を維持しません。これを行うと、リスト ビューの配置が崩れる奇妙な寸法のアイコンが生成される可能性があります。BufferedImage解決策は、おそらく16x16の新しいものを作成し、拡大縮小された画像をその上に中央揃えでレンダリングすることです。希望すれば実装できます!

2) ファイルが画像でない場合、または破損している場合、アイコンはまったく表示されません。プログラムがこのエラーを検出するのは、画像をロードまたはスケーリングするときではなく、画像のレンダリング中にのみであるように見えるため、これを事前に検出することはできません。ただし、問題 1 を修正すれば検出される可能性があります。

于 2010-12-09T11:58:07.377 に答える
5

画像を選択するfileDialog代わりに使用します。JfileChooser

FileDialog fd = new FileDialog(frame, "Test", FileDialog.LOAD);
String Image_path

fd.setVisible(true);
name = fd.getDirectory() + fd.getFile();
        image_path=name;
        ImageIcon icon= new ImageIcon(name);
        icon.setImage(icon.getImage().getScaledInstance(jLabel2.getWidth(),jLabel2.getHeight() , Image.SCALE_DEFAULT));
        jLabel2.setIcon(icon);
于 2012-11-10T17:27:22.713 に答える
0

各ファイルにデフォルトのアイコンを使用し、実際のアイコンを別のスレッドにロードできます (おそらく SwingWorker を使用しますか?)。アイコンがロードされると、SwingWorker はコールバックして FileView を更新できます。

単一の SwingWorker でうまくいくかどうか、または読み込まれるアイコンごとに 1 つ使用する方がよいかどうかはわかりません。

于 2010-11-04T12:18:29.357 に答える