torutkのブログ

ソフトウェア・エンジニアのブログ

JavaFX 2.0でアプリケーション作成(その5)

JavaFX 2.0でアプリケーション作成(その4) - torutkのブログ の続きです。前回で最低限のレイアウトが出来上がったので、今回は操作を実装します。

Buttonを押したら処理を実行する

Swingでは、JButtonにsetActionListenerメソッドでActionListener実装クラスのインスタンスを設定しておくと、そのJButtonが押されたときに、ActionListenerのactionPerformedメソッドが呼ばれるという仕組みでした。

JavaFX 2では、ButtonにsetOnActionメソッドでEventHandlerインタフェース実装クラスのインスタンスを設定しておくと、そのButtonが押されたときに、EventHandlerのhandleメソッドが呼ばれるという仕組みになります*1

コード断片は次のようになります。

        Button releaseButton = new Button("Release");
        releaseButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                semaphore.release();
                resultField.clear();
                updatePermits();
            }
        });

Java2 5.0で導入されたジェネリックスを使ったAPIとなっています。それ以外はほぼSwingと同様みたいです。

releaseButtonは、セマフォを解放する操作となります。そこで、このクラスのフィールドとして定義したjava.util.concurrent.Semaphoreインスタンスのrelease()を呼び、テキストフィールドを空欄としてから、独自に作成したupdatePermits()メソッドの中でsemaphoreのavailablePermits()の戻り値をテキストフィールドに設定しています。

コード全体を次に示します。

import java.util.concurrent.Semaphore;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

/**
 * セマフォの動きを理解するための可視化プログラムメイン。
 * @author toru
 */
public class SemaphoreView extends Application {
    private Semaphore semaphore = new Semaphore(1);
    private TextField permitsField;
    private TextField resultField;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Semaphoreの動きを理解する");

        BorderPane borderPane = new BorderPane();
        Label topLabel = new Label("Semaphoreへの操作とその結果");
        topLabel.setStyle("-fx-background-color: mistyrose");

        BorderPane.setAlignment(topLabel, Pos.CENTER);
        BorderPane.setMargin(topLabel, new Insets(6));
        borderPane.setTop(topLabel);

        GridPane semaphorePane = new GridPane();
        //semaphorePane.setGridLinesVisible(true);
        semaphorePane.setHgap(10);
        semaphorePane.setVgap(16);
        Label permitsLabel = new Label("利用可能な許可数:");
        semaphorePane.add(permitsLabel, 0, 0);

        permitsField = new TextField();
        semaphorePane.add(permitsField, 1, 0);

        Button tryButton = new Button("Try acquire");
        tryButton.setMaxWidth(Double.MAX_VALUE);
        tryButton.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                resultField.clear();
                boolean acquired = semaphore.tryAcquire();
                resultField.setText(String.valueOf(acquired));
                updatePermits();
            }
        });
        semaphorePane.add(tryButton, 0, 1);

        resultField = new TextField();
        semaphorePane.add(resultField, 1, 1);

        Button releaseButton = new Button("Release");
        releaseButton.setMaxWidth(Double.MAX_VALUE);
        releaseButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                semaphore.release();
                resultField.clear();
                updatePermits();
            }
        });
        semaphorePane.add(releaseButton, 0, 2);

        BorderPane.setMargin(semaphorePane, new Insets(4, 12, 4, 12));
        borderPane.setCenter(semaphorePane);

        updatePermits();

        primaryStage.setScene(new Scene(borderPane, 300, 200));
        primaryStage.show();
    }

    private void updatePermits() {
        permitsField.setText(String.valueOf(semaphore.availablePermits()));
    }
}

画面は次のようになります。利用可能な許可数が0になってからtryAcquireボタンを押した直後の状態です。


Semaphoreについて

java.util.concurrent.Semaphoreの動きについて、id:torutk:20120226に書きましたが、許可数を指定してSemaphoreインスタンスをnewしたとき、release()メソッドを繰り返し呼ぶと生成時にした許可数に関係なく利用可能な許可数が増大していきます。

その動作を確認するためにこのプログラムを作成し始めました。

*1:ActionEventは、javafx.event.ActionEventです。java.awt.event.ActionEventもあるので要注意です。