2013-05-04

【備忘録】JavaFX で複数のウィンドウを扱う

5 月の連休は、4/26 - 5/5 とまとまって取ることができました。この休みこそは普段の仕事を忘れ、ゆっくり JavaFX で自分が作りたいアプリケーション作りに没頭したいものだと思っていたのですが、なかなかそうはいきませんでした。

連休までに終わらせる予定だった仕事が終わらず、休みに入っても最初の三日間は自宅にこもって徹夜で対応していました。そのためすっかり昼夜が逆転してしまって調子を崩し、やっと自分のやりたいことが出きるようになった頃には、もう連休は後半にさしかかっています。

とにかく、GUI アプリケーションを作るための土台を作ろうと意気込んだのは良いのですが、どうも勝手がわかりません。メニューバーの ヘルプ からこのプログラムについて みたいなアイテムを選んで、別のウィンドウを表示する、と言った、ほんの基本的なことを実現するだけでも、なかなか納得したものができません。いろいろサイトを調べたりしてたどり着いた結果を備忘録としてもとめておきました。出来てしまえばなんてことはなかったのですが…。

やりたかったことは以下の通りです。

先述したように、メニューバーのメニュー Help から、項目 About を選んで、別ウィンドウを表示させるというものです。

メニューバーの Help メニューまわりは以下の様にします(メインプログラムの Ammonite.java の一部)。

public class Ammonite extends Application {
    ...
    (省略)
    ...
    @Override
    public void start(final Stage stage) {
       ...
       (省略)
       ...
        BorderPane root = new BorderPane();
        root.setPrefSize(300, 100);

        MenuBar bar = new MenuBar();
        root.setTop(bar);
       ...
       (省略)
       ...
        Menu helpMenu = new Menu("_Help");
        MenuItem aboutItem = new MenuItem("_About");
        aboutItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                Stage aboutStage = new DlgAbout(stage);
                aboutStage.show();
            }
        });
       ...
       (省略)
       ...
    }

    public static void main(String[] args) {
        launch(args);
    }
}

DlgAbout クラス (DlgAbout.java) は以下の様になります。プログラム固有の変数などが含まれていますので、あくまで参考まで。

public class DlgAbout extends Stage {

    Image logo = new Image(getClass().getResourceAsStream(Ammonite.imgLogo));
    Image info = new Image(getClass().getResourceAsStream(Ammonite.imgInfo));

    public DlgAbout(Stage owner) {
        initOwner(owner);
        initModality(Modality.APPLICATION_MODAL);
        initStyle(StageStyle.UTILITY);
        setTitle("About this");
        setResizable(false);
        getIcons().add(info);

        VBox vbox = new VBox();
        vbox.setId("dlg");

        Label lab1 = new Label(Ammonite.appName);
        lab1.setStyle("-fx-font-size: 20pt;");
        vbox.getChildren().add(lab1);

        Label lab2 = new Label("version " + Ammonite.appVer);
        vbox.getChildren().add(lab2);

        Label lab3 = new Label("COPYRIGHT(C) "
                + Ammonite.appYear + ", " + Ammonite.appAuthor);
        vbox.getChildren().add(lab3);

        Label lab4 = new Label("running on Java "
                + System.getProperty("java.version"));
        vbox.getChildren().add(lab4);

        Label lab5 = new Label();
        lab5.setGraphic(new ImageView(logo));
        lab5.setId("logo");
        vbox.getChildren().add(lab5);

        Button but1 = new Button("Close");
        vbox.getChildren().add(but1);
        but1.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                hide();
            }
        });

        Scene scene = new Scene(vbox);
        scene.getStylesheets().add(Ammonite.class.getResource("DlgAbout.css").toExternalForm());

        setScene(scene);
    }
}

一つできれば、他に別ウィンドウを作る場合にも応用が容易です。ある程度の汎用目的に使える基本的なダイアログを作ることもできます。

ちなみに DlgAbout クラスでは setResizable(false); として、ウィンドウサイズの変更をユーザー側ではできないように設定していますが、Fedora で使っているデスクトップ環境 LXDE では、この設定が効きません。Windows XP 上では下記の様に確かに設定が有効になっています。ウィンドウの右上隅の違いです(ウィンドウを最大/最小にするボタン(?)がありません)。一方で、info アイコンが左上隅に表示されません。

さて、この Ammonite というアプリケーションですが、エンジニアリングで必要な統計解析ができるツールになる予定ですが、まだ中身がありません。TableView を使いこなせなくてモタモタしています。むかしむかし、Tcl/Tk で作りかけていたアプリケーションを、JavaFX で作り直そうとしています。ベースの機能ができてくれば、SourceForge.net あたりにレポジトリを公開します。ご興味がある方は、何卒、気長に待っていてください。

参考サイト

  1. Set dialog Modality.APPLICATION_MODAL : Dialog « JavaFX « Java