Swingのモーダル画面から特定の画面を操作できるようにしたい

[改訂新版]Javaポケットリファレンス

はじめに

JavaFXの登場で今やSwingを使っている人は少ないかもしれませんが、私はクライアントアプリの開発でSwingを使っています。

JavaFX テクノロジーの概要

docs.oracle.com

 

もちろん最近開発されたものではなく、もう10年以上前に開発されたものを使い続けています。

そんなSwingアプリで久々にモーダル画面(ポップアップ)の表示制御を見直すことになりました。

具体的には「ポップアップが表示された状態でも、特定の画面(ヘルプ等)は操作できるようにしてほしい」というもの。

 

「そんなのできるなら最初からやってるんじゃない」と半信半疑で調べてみると、あっさりできました。

 

やっぱり最新バージョンのキャッチアップって大事だね、というのが今回のお話。

 

結論

以下のように、モーダル画面でDOCUMENT_MODALを指定する

dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);

 

 

経緯

「そもそもSwingにおけるモーダルとモードレスの関係ってどうなっているんだろう」と思って調べてみると、その辺りをまとめた記事がありました!

JFrameとJDialog

 

上の記事のテスト結果によると、やはり特定の画面だけモーダル制御から除外することはできないらしい。

 

早くも調査終了かと思いきや、ふとこんな記事を発見!

itpro.nikkeibp.co.jp

J2SE 5.0までは,モーダルの有無しか扱えませんでした。

Java SE 6ではより細かいモーダルの制御を行えるようになりました。

J2SE 5.0までのモーダルは,Dialog.ModalityTypeではAPPLICATION_MODAL(自分の子ウィンドウ以外は全てブロック)に相当します。

Java SE 6ではDOCUMENT_MODAL(自分の親ウィンドウだけブロック)を使用すれば,前述したヘルプ・ウィンドウの問題を解決できます。

 

まさに今回やりたかったこととピッタリ一致するわけです。

私が見ているSwingアプリは現在Java SE 6で動いていますが、初期構築はJ2SE 5.0以前(J2SE 1.4)だったので、そのままの仕様を引き継いでいたわけです。

 

というわけで、Dialog.ModalityTypeにより無事制御できました。めでたしめでたし。

 

まとめ

ちなみにやり方としては、モーダル画面(Dialog側)で制御する方法(ModalityType)と、親画面(Frame側)で制御する方法(ModalExclusionType)があります。

 

既にアプリケーションに多くのモーダル画面(Dialog側)を作成済みの場合、全てのモーダル画面にDOCUMENT_MODALを設定をするのは面倒なので、Frame側で制御した方が簡単なようにも思えますが、ModalExclusionTypeを使うとAPPLICATION_MODAL(従来のモーダル画面)がモーダル制御から除外されてしまうので、エラーポップアップなどが親画面から何度も重ねて表示されてしまうので注意が必要です。

なので、面倒でもDialog側で制御した方が確実だと思います。

 

ちなみに私の場合、モーダル画面にスーパークラスを作成して継承させ、スーパークラスのコンストラクタでAPPLICATION_MODALを設定するようにしました。

今後のバージョンアップ等で同じようなケースがあった場合、スーパークラスで切り替えられるようになるので、どうせ全部直すならスーパークラスを作成した方が良いと思います。