では前ページで紹介したコードで、どのような機能を実現しているのかを説明していきましょう。
ModifyActionHandlerクラスは、編集ボタンのイベントに対する処理を担当するインナークラスです。「toDoListModel. set(int index, Object target);」にて、toDoListModelのindex番目のデータ、targetを設定することができます。
RemoveActionHandlerクラスは、削除ボタンのイベントに対する処理を担当するインナークラスです。「setButtonsEnabled(false)」にて、すべてのボタンを非活性化し、その後doLongTaskにて、10秒待ちます(10秒待つ理由は後述します)。
その後、「toDoListModel.remove(int index);」にて、toDoListModelのindex番目のデータを削除します。削除した後、「setButtonsEnabled(true)」にて、すべてのボタンを活性化します。
TodoListSelectionHandlerクラスは、ToDoリストで選択した行の内容をテキストフィールドに反映します。
さて、削除処理にあえて10秒間待つ処理を入れました。もし単純にこれを処理してしまうと、削除処理中は何も操作できなくなってしまいます。これでは、アプリケーションを使う側は削除を行うたびにいらいらしてしまいます。このような事態を避けるために、時間のかかる処理を別のスレッドに任せて、ユーザーが操作を行えるようにしながらバックグラウンドで処理を行うということをします。
ここでは、RemoveThreadクラス内で別スレッドを呼び出し、時間のかかる処理(doLongTask)と削除処理を実行させることによって実現しています。
時間のかかる処理を行った後、最後にSwingUtilities.invokeLater()を呼び出しています。これは、「toDoListModel.remove(int index);」および「setButtonsEnabled(true)」の2つの処理をイベントディスパッチスレッドで実行させるために使っています。なぜ、わざわざこのようなことをするのでしょうか?
Swingのスレッドポリシーとして、次のようなものがあります。
「コンポーネントの「状態に依存する」あるいは「状態に影響を与える」
「処理はすべてイベントディスパッチスレッド上で動作しなければならない」
これはいい換えると、Swingの描画に関連する処理は、シングルスレッドで処理しなくてはならないということです。そして、そのシングルスレッドがイベントディスパッチスレッドなのです。このルールにのっとるため、わざわざSwingUtilities.invokeLater()を使っているのです。
今回の実装でも、sleepは描画に関係がないため別スレッドを生成して実行させましたが、描画に関する処理(toDoListModel.remove、setButtonsEnabled)はイベントディスパッチスレッドで実行させるようにしています。
「SwingAppMain」クラスのmainメソッド内ではSwingUtilities.invokeLater を呼び出し、Frameを描画する処理をイベントディスパッチスレッドに実行させています。mainメソッドのスレッドが描画しているわけではありません。
「SwingAppMain」クラスのmainメソッドとcreateAndShowTodoListメソッドでは、SwingUtilities.isEventDispatchThreadというメソッドが呼び出されています。これは、実行されているスレッドがイベントディスパッチスレッドであればtureを、別のスレッドであればfalseを返します。
「SwingAppMain」を実行すると、コンソールに以下のように表示されます。
main : false createAndShowTodoList : true
createAndShorTodoListメソッドは、イベントディスパッチスレッド上で実行されていることが分かりますね。
本連載では計6回にわたってSwingの基本を解説してきました。
簡単なGUIアプリケーションだけならこれで作成できるようになりましたが、GUIの世界はもっと広く、深いものです。これを機に、GUIアプリケーションの世界に踏み込み、GUIの面白さに触れていただければ幸いです。
Copyright © ITmedia, Inc. All Rights Reserved.