ImageIcon Refresh: アイコンの再読み込み2008年07月07日 12時00分48秒

Java で画像を表示する時には、javax.swing.ImageIcon を用いる。new ImageIcon(path) で生成し、Component に入れると表示する。元々は、アイコンの様に小さい画像向けのようだが、大きい画像も処理できる。この実装には直接は記されていない落とし穴がある。

このクラスに画像へのパスを指定してクラスを生成する。そして、何らかの要因で画像が書き換えられたので、再度クラスを生成して、新しい画像を表示しようとしても出来ない。ImageIcon は Refresh が出来ない。これは、画像が内的な要因でも外的に差し替えられたとしてもだ。

少し調べたところ、他の人達も同じ問題に当たっていた様だが、どうも原因以外のことで余計な暴言の交換になっているだけで、解決の糸口も掴めていないのが多いようだった。

これは、ImageIcon の後ろにある実装によってキャッシュされているのが原因だ。ImageIcon にて、URL や String を用いて、パスを渡すと、java.awt.Toolkit が画像を読み込み生成する。実は、この Toolkit が 同じアイコンを複数の場所から読み込んだ時に、同じ処理を繰り返すのを防ぐ実装になっている。

まずは、ImageIcon の一つの実装。


    /**
     * Creates an ImageIcon from the specified file. The image will
     * be preloaded by using MediaTracker to monitor the loading state
     * of the image.
     * @param filename the name of the file containing the image
     * @param description a brief textual description of the image
     * @see #ImageIcon(String)
     */
    public ImageIcon(String filename, String description) {
	image = Toolkit.getDefaultToolkit().getImage(filename);
        if (image == null) {
            return;
        }
	this.filename = filename; 
        this.description = description;
	loadImage(image);
    }

こちらでは、Toolkit から読み込んでいる。そちらを見る必要がある。

こちらが、Toolkit のに書かれているコメントだ。


    /**
     * Returns an image which gets pixel data from the specified URL.
     * The pixel data referenced by the specified URL must be in one
     * of the following formats: GIF, JPEG or PNG.
     * The underlying toolkit attempts to resolve multiple requests
     * with the same URL to the same returned Image.
     * Since the mechanism required to facilitate this sharing of
     * Image objects may continue to hold onto images that are no
     * longer of use for an indefinite period of time, developers
     * are encouraged to implement their own caching of images by
     * using the createImage variant wherever available.
     * @param     url   the URL to use in fetching the pixel data.
     * @return    an image which gets its pixel data from
     *                         the specified URL.
     * @see #createImage(java.net.URL)
     */
    public abstract Image getImage(URL url);

キャッシュをしている事は明記してある。しかし、これからでは画像が更新された時の動作は示されていない。他の人達が、更新された画像を再描画出来ないので悩んでいたり、実際に試した結果だと、ファイルの更新情報は見ていない。

更新されたファイルを読み込むには、ImageIcon (Image image) や ImageIcon (byte[] imageData) など、Toolkit の createImage を呼ばないインターフェースを用いる。