2014年6月7日土曜日

[Java] SwingのUIを無限ループで更新するには

How to update the UI in an Infinite loop
SwingはJavaのGUIアプリケーションの開発及び実行環境です。
Javaでアプリ開発できるAndroidに比べるとUI(画面)更新にだいぶ違いがあるので悩んだところをまとめてみました。

開発環境

・32bit Windows7
・Eclipse 3.5
・その他Eclipse用日本語化プラグイン、Jstyleなど


Swing用プラグインのインストール

EclipseでSwingを利用するにあたりSwing Designerというプラグインをインストールしました。
ヘルプ - 新規ソフトウェアのインストール
を開き、作業対象に
http://download.eclipse.org/windowbuilder/WB/release/R201309271200/4.3/
と入力し
Swing Designer
WindowBuilder Engine
の2つをインストールしました。

Swing Designerの他にもVisual Swingというプラグインも公開されているようです。


Swing用プロジェクトの作成

簡単な例としてデジタル時計を作ってみます。
新規にJava プロジェクトを作成します。
JFlameのサブクラスを作成します。
JFlameにLabelを一つ追加しました。

約1秒間隔でLabelに現在時刻を表示することを目標にします。


悪い例



コンパイルエラーはありません。
ですが実行しても何も変化しないか、実行時エラーが出たりすると思います。
コンストラクターで無限ループしてるのでコンストラクターが終わりません。
停止させるにはデバッグウィンドウの終了ボタンをクリックしてください。
もし正常に動作するように見えてもこのまま使ってはいけません。


Swingでの約束事

・ループ処理は新しいスレッドで処理する
・UI更新はSwingUtilities.invokeLater(Runnable doRun)で処理する

上の例ではループ処理とUI更新処理を同じスレッドで実行しています。
約束事を守ってないのでUI更新が保証されません。
ちなみに今回のループ処理のようなスレッドをワーカースレッド、UI更新処理のためのスレッドをイベントディスパッチスレッドと呼ぶようです。
イベントディスパッチスレッドで処理したい内容を SwingUtilities.invokeLaterの中に書きます。
UI更新はSwingUtilities.invokeLaterで処理する必要があります。


修正した結果



これで正常に動作しました。
今回は使いませんでしたが、UI更新をイベントディスパッチスレッドの最後に処理する SwingUtilities.invokeAndWait(Runnable doRun) というメソッドもあります。


まとめ

実際に無限ループを処理することはあまりないと思います。
なので今回のサンプルは実用性がありません。

ですが、Webサーバーやデータベースサーバーにアクセスしてユーザーを待たせるようなSwingアプリケーションを作るときは
・サーバーへのアクセスは新しいスレッドで処理する
・UI更新は SwingUtilities.invokeLater で処理する
・SwingUtilities.invokeLater の中でUI更新以外の処理をさせない
という設計にするといいと思います。



関連ブログ

[Android] PrintStream#printfの最適化(SDK r08でのエラーを別の方法で解決する)
[Android] Javaのstaticクラスから非sataticメソッドを呼び出すには
[Blender] obj2opengl.plをJava用に改造する
[Windows8][Android] EclipseをXP互換モードで起動する理由(Can't bind to local 8600 for debugger)
[Android] Activityに時計を表示する(Activityの非同期更新)
[Android] アナログ時計のアプリを作ってみました
[Android] ストップウォッチアプリを作ってみました
[Android] 方位センサーを使ってコンパスアプリを作る
[Android] OpenGLの簡易画像ビュアーにSDカード内の画像を表示する
[Android] Android-SDKでやってはいけないこと


以上、参考になれば幸いです。

0 件のコメント:

コメントを投稿