JavaFX 2.0でアプリケーション作成(その7) - torutkのブログの続きです。
JavaFX 2.1リリースとNetBeansプロジェクト設定変更
JavaFX 2.1がリリースされ、Java SE Development Kit 7u4をインストールすると、JavaFX 2.1がインストールされるようになります。JavaFX 2.1の新機能については日本オラクルのブログに紹介があります。
NetBeansのJavaFXアプリケーションプロジェクトでプログラミングをしていた場合、Java SE 7のアップデートによりJavaFX 2.0からJavaFX 2.1に更新されるため、設定の変更が必要になります。
[ツール]メニュー>[Javaプラットフォーム]を選択すると、「Javaプラットフォームマネージャ」ダイアログが表示されます。[JavaFX]タブをクリックすると、JavaFXへのパスが記載されていますが、前のバージョンの2.0となっているため、Java SE 7 Update4にした結果エラーとなってしまったものです。
JavaFX 2.1を指すように修正します。
画面レイアウト追加
セマフォの獲得(ブロッキング呼び出し)を行うSemaphore.acquireメソッドを別スレッドで実行する機能を追加します。GUIとして、ボタンの追加、別スレッドが実行している間はProgressBarを表示させます。
セマフォの獲得を実行するボタンを追加した画面を次に示します。
利用可能な許可数が0のときに[Acquire]ボタンを押すと、セマフォのacquireメソッドを呼び出します。acquireメソッドは許可数が1以上になるまでブロックするので、別スレッドで待ち続け、ProgressBarを表示します。
Acquireボタン
まず、ボタンのビューを追加します。ボタンを押した時の振る舞いは後程記述します。
public void start(Stage primaryStage) { : Button acquireButton = new Button("Acquire"); acquireButton.setMaxWidth(Double.MAX_VALUE); semaphorePane.add(acquireButton, 0, 3); : }
スレッドの導入
Acquireボタンを押したときに、セマフォ獲得するスレッドを起動します。
スレッドは、javafx.concurrent.Serviceクラスを継承して作成することにします。Taskクラスの場合、一度実行すると、Taskインスタンスは破棄して新たにTaskインスタンスを作り直す必要があるため、何回も実行可能なボタンやプログレスバーに結び付ける場合は、Serviceの方が適しているからです。
AcquireServiceクラスのコード
import java.util.concurrent.Semaphore; import javafx.concurrent.Service; import javafx.concurrent.Task; public class AcquireService extends Service { private Semaphore semaphore; public AcquireService(Semaphore semaphore) { this.semaphore = semaphore; } @Override protected Task createTask() { Task<Void> task = new Task<Void>() { @Override protected Void call() throws Exception { updateProgress(-1, -1); semaphore.acquire(); updateProgress(1, 1); return null; } }; return task; } }
Serviceクラスの実装は、createTaskをオーバーライドし、スレッドで実行したい処理を記述することです。結局Serviceクラスを実装することは、Taskクラスを実装することでもあるのですが・・・。
別スレッドで実行したいコードは次です。
semaphore.acquire();
このメソッドが長期間ブロックされる可能性があるためです。このメソッドの呼び出し前後でプログレスバーの制御を記述します。
updateProgress(-1, -1); semaphore.acquire(); updateProgress(1, 1);
updateProgressメソッドは、javafx.concurrent.Taskクラスに定義済みのメソッドで、プログレスバー等の進捗表示を制御します。
ボタンを押すとこのタスクを実行する処理をstartメソッドに追記します。
acquireService = new AcquireService(semaphore); acquireButton.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { acquireService.restart(); } });
プログレスバーをサービスに結び付け、updateProgressメソッドが実行できるお膳立てをしておきます。startメソッドに追記します。
progressBar.progressProperty().bind(acquireService.progressProperty());
セマフォ獲得呼び出しをしていないときはプログレスバーを非表示にしたいため、次の処理をstartメソッドに追記します。
progressBar.visibleProperty().bind(acquireService.runningProperty());
ついでに、セマフォ獲得スレッド実行中のときはAcquireボタンを非活性化します。startメソッドに追記します。
acquireButton.disableProperty().bind(acquireService.runningProperty());
基本的な振る舞いはできましたが、セマフォ獲得メソッド呼び出しから復帰後、利用可能な許可数の欄を最新に更新する必要があります。次回、この処理を追加します。
記事一覧
- JavaFX 2.0最初の一歩 - torutkのブログ
- JavaFX 2.0でアプリケーション作成(その1) - torutkのブログ
- JavaFX 2.0でアプリケーション作成(その2) - torutkのブログ
- JavaFX 2.0でアプリケーション作成(その3) - torutkのブログ
- JavaFX 2.0でアプリケーション作成(その4) - torutkのブログ
- JavaFX 2.0でアプリケーション作成(その5) - torutkのブログ
- JavaFX 2.0でアプリケーション作成(その6) - torutkのブログ
- JavaFX 2.0でアプリケーション作成(その7) - torutkのブログ