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開発につながります。


コメント