【Java】ウィンドウに画像を描画する
本稿はJFrameクラスで作成したウィンドウに画像を描画する方法を紹介します。
ゲームを作成する場合は画像を描画して実装することがほとんどになると思うので、必ず使えるようになりましょう。
画像を読み込んで表示
まず初めに、画像を読み込む処理を見ていきましょう。
ToolkitクラスやImageIOクラスを利用することで簡単に読み込み処理を実装できます。
今回は、Toolkitクラスで読み込む方法を紹介します。
プログラムならImage img = Tookit.getDefaultToolkit().getImage(画像へのパス)のようにしてImageオブジェクトの取得ができます。
読み込んだ画像はGraphicsクラスのメソッドであるdrawImageメソッドを呼び出すだけです。
drawImage(Imageオブジェクト, x座標, y座標, 監視コンポーネント)と指定します。
良くわからない監視コンポーネントの引数ですが、指定しておくと画像を監視し、必要な時に再描画命令を出してくれます。
例えば、アニメーションありのgif画像の場合、指定しておくとアニメーションを自動で描画してくれます。利用する場合は画像が表示されているコンポーネントオブジェクトを指定しておけばよいでしょう。
表示する画像は、私が練習もかねてお絵描きした下記の画像を利用します。
sample.png
(なんか前髪などいろいろおかしい気がしますが気にしないでくださいw)
それでは、いつも通りのウィンドウの表示と画像を読み込んで表示するところまでを行うサンプルをご覧ください。
import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.JPanel; public class Test{ public static void main(String[] args) { GameWindow gw = new GameWindow("テストウィンドウ",400,300); DrawCanvas dc = new DrawCanvas(); gw.add(dc); gw.setVisible(true); } } class GameWindow extends JFrame{ public GameWindow(String title, int width, int height) { super(title); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(width,height); setLocationRelativeTo(null); setResizable(false); } } class DrawCanvas extends JPanel{ Image img = Toolkit.getDefaultToolkit().getImage("sample.png"); public void paintComponent(Graphics g) { super.paintComponent(g); //画像の表示 g.drawImage(img, 0, 0, this); } }
x=0,y=0の座標に読み込んだ画像が表示できました。
画像の拡大縮小描画
画像をプログラムから拡大縮小し、描画したい場合はサイズ指定できるメソッドを使用します。
drawImage(Imageオブジェクト, x座標, y座標, 横幅, 縦幅, 監視コンポーネント)で指定しましょう。
それではDrawCanvasのみ修正し、画像を拡大縮小してみましょう。
class DrawCanvas extends JPanel{ Image img = Toolkit.getDefaultToolkit().getImage("sample.png"); public void paintComponent(Graphics g) { super.paintComponent(g); //縮小描画 g.drawImage(img, 0, 0, 120, 90, this); //横長の画像を描画 g.drawImage(img, 0, 100, 400, 120, this); } }
幅や高さを負の数にすると反転した画像を描画することもできます。
上下左右反転して描画したい場合は下記のようにして実装できます。
class DrawCanvas extends JPanel{ Image img = Toolkit.getDefaultToolkit().getImage("sample.png"); public void paintComponent(Graphics g) { super.paintComponent(g); //上下反転画像を描画 g.drawImage(img, 400, 300, -400, -300, this); } }
画像の範囲指定描画
画像を描画する際に画像の一部を切り取って描画することも可能です。
よくフリーゲームなどで複数のドット絵が一枚の画像で用意されているものが合ったりしますが、そのような画像を切り取り描画することにも使えます。
ちょっと引数が長いですが、余裕のある方は覚えておくと良いかもしれません。
drawImage(Imageオブジェクト, 描画開始x座標, 描画開始y座標, 描画終了x座標, 描画終了y座標, 画像の切取開始x座標, 画像の切取開始y座標, 画像の切取終了x座標, 画像の切取終了y座標, 監視コンポーネント)と指定してください。
画像の切り取り座標を指定して、描画先座標に描画できるわけです。
実際に先ほどの画像の二つの顔を分けて表示してみましょう。
class DrawCanvas extends JPanel{ Image img = Toolkit.getDefaultToolkit().getImage("sample.png"); public void paintComponent(Graphics g) { super.paintComponent(g); //画像の左側を描画 g.drawImage(img, 0, 0, 160, 200, 0, 0, 150, 200, this); //画像の右側を描画 g.drawImage(img, 200, 0, 360, 200, 150, 0, 300, 200, this); } }
画像の読み込み待ち
読み込んだ画像はロードが完了するまで待機してくれる、MediaTrackerクラスを利用します。
これを利用すると、drawImageの監視コンポーネントの引数にnullを指定しても画像が表示できたり、画像監視による自動再描画命令を出さないようにしたい場合に利用できます。
MediaTrackerには、コンストラクタにComponentを指定する必要がありますが、基本的には表示しているコンポーネントオブジェクトを指定しておけばよいでしょう。
画像のロードが終わらないまま描画処理を行っても何も描画されないので、気を付けてください。
それではサンプルです。
class DrawCanvas extends JPanel{ Image img; DrawCanvas(){ Image img = Toolkit.getDefaultToolkit().getImage("sample.png"); MediaTracker mt = new MediaTracker(this); mt.addImage(img,0); try{ mt.waitForAll(); }catch(Exception e){ e.printStackTrace(); } this.img = img; } public void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(img, 0, 0, null); } }
drawImageの最後の引数にnullを指定しましたが、画像が表示されました。
ディスカッション
コメント一覧
質問よろしいでしょうか。
DrawCanvasクラスのメソッドのpublic void paintComponent(Graphics g)はどのタイミングで呼び出しているのでしょうか。
ぱっと見ほかのクラスで呼び出されているように見えません。
今更ですがコメントを見たので返信しておきます。
paintComponentはJava側が自動で呼び出してくれるメソッドになります。
呼び出されるタイミングはJava側が必要と判断した時です。
今回の場合はsetVisibleでウィンドウを表示したときにJava側が描画が必要と判断しpaintComponentが呼び出されます。
そのほか最小化してからもう一度開いたときなどにも呼び出されることがあります。
このメソッドを意図的に呼び出したいときはJPanelインスタンスのrepaintメソッドを実行することでpaintComponentを呼び出せます。