web-dev-qa-db-ja.com

JPanelに画像を追加する方法

私はその場で生成するJPEGとPNG画像を追加したいと思う JPanel を持っています。

これまでに Swingチュートリアル で見たすべての例、特に Swingの例 ではImageIconsを使用しています。

私はこれらの画像をバイト配列として生成していますが、通常は例で使用されている一般的なアイコンよりも大きい640 x 480です。

  1. JPanelでそのサイズの画像を表示するためにImageIconクラスを使用することに(パフォーマンスまたは他の)問題はありますか?
  2. 通常のやり方は何ですか?
  3. ImageIconクラスを使用せずにJPanelに画像を追加する方法

編集 :チュートリアルとAPIをもっと慎重に調べると、ImageIconを直接JPanelに追加できないことがわかります。代わりに、それらはJLabelのアイコンとして画像を設定することによって同じ効果を達成します。これはちょうどいい感じではありません...

328
Leonel

これが私のやり方です(画像のロード方法についてもう少し詳しく説明します)。

import Java.awt.Graphics;
import Java.awt.image.BufferedImage;
import Java.io.File;
import Java.io.IOException;
import Java.util.logging.Level;
import Java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ImagePanel extends JPanel{

    private BufferedImage image;

    public ImagePanel() {
       try {                
          image = ImageIO.read(new File("image name and path"));
       } catch (IOException ex) {
            // handle exception...
       }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, this); // see javadoc for more info on the parameters            
    }

}
242
Brendan Cashman

あなたがJPanelsを使用しているなら、おそらくSwingを使用しています。これを試して:

BufferedImage myPicture = ImageIO.read(new File("path-to-file"));
JLabel picLabel = new JLabel(new ImageIcon(myPicture));
add(picLabel);

画像は今スイングコンポーネントです。他のコンポーネントと同様にレイアウト条件の影響を受けます。

507
Fred Haslam

Fred Haslamの方法はうまくいきます。私は私のjarファイル内の画像を参照したいので、私はしかし、ファイルパスに問題がありました。これを行うために、私は使用しました:

BufferedImage wPic = ImageIO.read(this.getClass().getResource("snow.png"));
JLabel wIcon = new JLabel(new ImageIcon(wPic));

この方法でロードする必要があるのは有限個(約10個)の画像しかないので、それは非常にうまく機能します。正しい相対ファイルパスを指定せずにファイルを取得します。

33
shawalli

サブクラス化する必要はないと思います。 Jlabelを使うだけです。画像をJlabelに設定できます。そのため、Jlabelのサイズを変更してから画像を埋めます。大丈夫です。これが私のやり方です。

32
CoderTim

Free SwingX ライブラリのJXImagePanelクラスを使うことであなた自身のComponentサブクラスを完全にロールすることを避けることができます。

ダウンロード

20
Dan Vinton
JLabel imgLabel = new JLabel(new ImageIcon("path_to_image.png"));
11
user1597002
  1. 非常に大きな画像で発生する可能性がある一般的な問題以外に、問題はないはずです。
  2. 単一のパネルに複数の画像を追加することを考えているのであれば、ImageIconsを使用します。単一の画像の場合は、JPanelのカスタムサブクラスを作成し、そのpaintComponentメソッドをオーバーライドして画像を描画することを考えます。
  3. (2を参照)
8
Michael Myers

JPanelをサブクラス化することができます - これは私のImagePanelからの抜粋です。これは上/左、上/右、中央/中央、下/左または下/右の5つの場所のいずれかに画像を置きます。

protected void paintComponent(Graphics gc) {
    super.paintComponent(gc);

    Dimension                           cs=getSize();                           // component size

    gc=gc.create();
    gc.clipRect(insets.left,insets.top,(cs.width-insets.left-insets.right),(cs.height-insets.top-insets.bottom));
    if(mmImage!=null) { gc.drawImage(mmImage,(((cs.width-mmSize.width)/2)       +mmHrzShift),(((cs.height-mmSize.height)/2)        +mmVrtShift),null); }
    if(tlImage!=null) { gc.drawImage(tlImage,(insets.left                       +tlHrzShift),(insets.top                           +tlVrtShift),null); }
    if(trImage!=null) { gc.drawImage(trImage,(cs.width-insets.right-trSize.width+trHrzShift),(insets.top                           +trVrtShift),null); }
    if(blImage!=null) { gc.drawImage(blImage,(insets.left                       +blHrzShift),(cs.height-insets.bottom-blSize.height+blVrtShift),null); }
    if(brImage!=null) { gc.drawImage(brImage,(cs.width-insets.right-brSize.width+brHrzShift),(cs.height-insets.bottom-brSize.height+brVrtShift),null); }
    }
7
Lawrence Dol

JPanelはほとんどの場合サブクラスにとって間違ったクラスです。なぜあなたはJComponentをサブクラス化しないのですか?

ImageIconには、コンストラクタが画像の読み込みをブロックするという点でわずかな問題があります。アプリケーションjarから読み込むときにはそれほど問題ではありませんが、ネットワーク接続を介して読んでいる可能性がある場合はおそらくそうです。 JDKのデモでも、MediaTrackerImageObserver、および友人を使用するAWT時代の例はたくさんあります。

私が取り組んでいるプライベートプロジェクトでも、非常によく似たことをしています。これまで私は問題なく(メモリを除く)最大1024 x 1024の画像を生成していて、パフォーマンス上の問題もなく非常に素早くそれらを表示することができます。

JPanelサブクラスのPaintメソッドをオーバーライドするのはやり過ぎであり、あなたがする必要があるよりも多くの作業を必要とします。

やり方は次のとおりです。

Class MapIcon implements Icon {...}

OR

Class MapIcon extends ImageIcon {...}

画像を生成するために使用するコードはこのクラスになります。 paintIcon()が呼び出されたときに描画するためにBufferedImageを使用します。g.drawImvge(bufferedImage)を使用します。これにより、画像を生成している間に行われる点滅の量が減り、スレッド化することができます。

次にJLabelを拡張します。

Class MapLabel extends Scrollable, MouseMotionListener {...}

これは、スクロールペインに画像を配置したいためです。画像の一部を表示し、必要に応じてユーザーにスクロールさせます。

そこで私は、MapIconだけを含むMapLabelを保持するためにJScrollPaneを使います。

MapIcon map = new MapIcon (); 
MapLabel mapLabel = new MapLabel (map);
JScrollPane scrollPane = new JScrollPane();

scrollPane.getViewport ().add (mapLabel);

しかしあなたのシナリオでは(ちょうど毎回全体の画像を見せる)。 MapLabelを一番上のJPanelに追加し、それらをすべて画像のフルサイズに合わせるようにする必要があります(GetPreferredSize()をオーバーライドすることによって)。

6

プロジェクトディレクトリにソースフォルダを作成します。この場合は、Imagesと呼びます。

JFrame snakeFrame = new JFrame();
snakeFrame.setBounds(100, 200, 800, 800);
snakeFrame.setVisible(true);
snakeFrame.add(new JLabel(new ImageIcon("Images/Snake.png")));
snakeFrame.pack();
5
user4294909

この答えは@ shawalliの答えを補完するものです...

私は私のjarファイル内でも画像を参照したいのですが、BufferedImageを持っているのではなく、これを単純にしました。

 JPanel jPanel = new JPanel();      
 jPanel.add(new JLabel(new ImageIcon(getClass().getClassLoader().getResource("resource/images/polygon.jpg"))));

あなた自身のComponentsとSwingXライブラリとImageIOクラスの使用を避けることができます:

File f = new File("hello.jpg");
JLabel imgLabel = new JLabel(new ImageIcon(file.getName()));
3
Muskovets

私は多くの答えを見ることができますが、実際にはOPの3つの質問に対処するわけではありません。

1) パフォーマンスに関する言葉:あなたのディスプレイアダプタの現在の解像度と色深度に一致する正確なピクセルバイト順を使用できない限り、バイト配列はおそらく非効率的です。

最高の描画パフォーマンスを実現するには、画像を現在のグラフィック構成に対応する型で生成されたBufferedImageに変換するだけです。 https://docs.Oracle.com/javase/tutorial/2d/images/drawonimage.html にあるcreateCompatibleImageを参照してください。

プログラミングの手間をかけずに数回描画した後、これらの画像は自動的にディスプレイカードのメモリにキャッシュされるので(これはSwingではJava 6以降の標準です)、したがって実際の描画にはごくわずかな時間がかかります - ifあなたは画像を変えませんでした。

イメージを変更すると、メインメモリとGPUメモリの間で追加のメモリ転送が発生します。これは時間がかかります。そのため、画像をBufferedImageに「再描画」することは避け、getPixelおよびsetPixelを絶対に行わないでください。

たとえば、ゲームを開発している場合、すべてのゲームアクターをBufferedImage、次にJPanelの順に描画するのではなく、すべてのアクターを小さいBufferedImageとしてロードし、それらを1つずつJPanelコードに描画する方がはるかに高速です。それらの適切な位置 - このように、キャッシュのための画像の初期転送を除いて、メインメモリとGPUメモリとの間の追加のデータ転送はありません。

ImageIconは内部でBufferedImageを使用します - しかし基本的にproperグラフィックモードでBufferedImageを割り当てることが重要であり、これを正しく行う努力はありません。

2) これを行う通常の方法は、JPanelのオーバーライドされたpaintComponentメソッドでBufferedImageを描画することです。 Javaは、GPUメモリにキャッシュされたVolatileImagesを制御するバッファチェーンなど、その他にも豊富な機能をサポートしていますが、Java 6以降、これらのGPUアクセラレーションの詳細を一切公開せずに適切な処理を行う必要はありません。

GPUアクセラレーションは半透明の画像を引き伸ばすなどの特定の操作では機能しない場合があることに注意してください。

3) 追加しないでください。上記のようにペイントするだけです。

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.drawImage(image, 0, 0, this); 
}

画像がレイアウトの一部である場合、「追加」は意味があります。 JPanelを塗りつぶす背景画像または前景画像としてこれが必要な場合は、単にpaintComponentを描画します。あなたのイメージを表示することができる一般的なSwingコンポーネントを作りたいなら、それは同じ話です(あなたはJComponentを使って、そのpaintComponentメソッドをオーバーライドすることができます) - そしてGUIコンポーネントのレイアウトにthisを加えます。

4) 配列をバッファ画像に変換する方法

あなたのバイト配列をPNGに変換してそれをロードすることは非常にリソース集約的です。もっと良い方法は、既存のバイト配列をBufferedImageに変換することです。

そのためには:ループには使用しないでくださいそしてピクセルをコピーしてください。それはとてもとても遅いです。代わりに:

  • bufferedImageの推奨バイト構造を学びましょう(現在、RGBまたはRGBAを想定するのが安全です。これは1ピクセルあたり4バイトです)。
  • スキャンラインを学び、使用中のスキャンサイズを調べます(例:142ピクセル幅の画像があるかもしれませんが、実際には256ピクセル幅のバイト配列として保存されます)。 )
  • これらの原則に従って配列を構築したら、BufferedImageのsetRGB配列メソッドを使用して、配列をBufferedImageにコピーできます。
0
Gee Bee