BufferedImageのGraphics2D描画が即時表示されない原因とSwingで正しく描画する方法

Java

JavaのSwingでBufferedImageとGraphics2Dを使って描画していると、「描いたはずの図形がすぐ画面に出ない」「一部だけ表示されて後からまとめて表示される」といった挙動に遭遇することがあります。これはバグではなく、Swingの描画モデルとスレッド処理の仕組みに起因するものです。本記事では、この現象の理由と正しい扱い方を整理します。

描画がすぐ反映されない理由

Swingは描画結果を即時に画面へ反映するのではなく、内部のバッファに保持してから再描画時にまとめて表示します。

そのためGraphics2Dで描画しても、paint処理が走るまで画面更新されない場合があります。

例えばBufferedImageに描いた内容は、JFrameのrepaintが呼ばれるまで更新されません。

Swingの描画モデルとイベントディスパッチスレッド

Swingは「イベントディスパッチスレッド(EDT)」という専用スレッドで描画を管理しています。

mainスレッドから直接描画処理を行っても、画面更新はEDTのタイミングに依存します。

例えばsetVisible(true)やrepaint()が描画更新のトリガーになります。

BufferedImageの役割と誤解

BufferedImageは画面そのものではなく、あくまでメモリ上の画像データです。

Graphics2Dで描画しても、それは画像に書き込んでいるだけで画面には直接反映されません。

例えば画像編集ソフトのキャンバスのように、最終的に表示処理が必要です。

Thread.sleepで挙動が変わる理由

Thread.sleepを入れると表示が変わるのは、EDTに処理のタイミングが渡るためです。

これは描画処理の同期問題が一時的に解消されているだけで、正しい解決方法ではありません。

例えば0msでは全部表示されるが、1msで一部だけ表示されるのはスケジューリングの影響です。

正しい設計:描画はpaint系メソッドに任せる

Swingでは描画処理はpaintComponentやrepaintを通じて行うのが基本です。

BufferedImageを更新した後にrepaintを呼び出すことで安全に画面へ反映できます。

例えばJLabelにImageIconとして設定した画像もrepaintで更新されます。

mainから直接描画したい場合の考え方

教育用途などでmain内だけで完結させたい場合でも、内部的には必ずSwingの描画サイクルを通る必要があります。

そのため完全にsetVisibleやrepaintを排除することはできません。

例えば「描いたら即表示」は内部的に再描画を隠しているだけの仕組みです。

まとめ

BufferedImageへの描画が即時に画面へ反映されないのはSwingの仕様であり、EDTと再描画処理によって制御されています。

Thread.sleepなどで解決するのではなく、repaintやpaintComponentを前提とした設計が正しい方法です。

描画と表示の役割を分離して理解することが安定したGUI開発につながります。

コメント

タイトルとURLをコピーしました