JavaでDialogクラスやJDialogクラスを使用してダイアログを表示するとしましょう。

ダイアログを表示したときに,ダイアログを表示させた元のフレームなどが操作できなくなることがあります。このようなダイアログをモーダルなダイアログといいます。

モーダルなダイアログは,そのダイアログで入力などの操作が必要であることをユーザーにわからせるのに効果的です。

DialogクラスやJDialogクラスは,コンストラクタの引数でモーダルかどうかを指定できます。また,setModalメソッドで指定することも可能です。

一方,JOptionPaneクラスのshowXXXXDialogメソッド(XXXXの部分はInputやConfirmなどが入ります)で表示した場合は,ダイアログはモーダルになります。

J2SE 5.0までは,モーダルの有無しか扱えませんでした。通常はこれだけで問題ありません。しかし,一つのアプリケーションで複数のウィンドウを扱う場合はちょっと困ってしまうこともあります。

例えば,通常のオペレーションを行うウィンドウ以外に,ヘルプを表示するウィンドウがある場合を考えてみます。メインのウィンドウでモーダルのダイアログを表示すると,ヘルプ・ウィンドウへのアクセスもブロックされてしまいます。

ユーザーとしては,表示されたダイアログのヘルプを見たくても,ブロックされてしまっているのでヘルプ・ウィンドウを操作できません。これはちょっと困りものです。

かといって,ダイアログをモーダルにしないと,本来のモーダルの意味がなくなってしまいます。

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

新しいモーダル・モデル

Java SE 6ではダイアログのモーダルをDialog.ModalityTypeというenumで表します。取りうる値は次の4種類です。

表1 Dialog.ModalityType
説明
MODELESS ウィンドウのブロックを行わない
APPLICATION_MODAL アプリケーションのすべてのウィンドウをブロックする
ただし,ダイアログの子供のウィンドウはブロックしない
DOCUMENT_MODAL 自身の親のウィンドウはブロックするが,他のウィンドウはブロックしない
ただし,ダイアログの子供のウィンドウはブロックしない
TOOLKIT_MODAL 同じToolkitオブジェクトを使用して作成されたウィンドウをブロックする
ただし,ダイアログの子供のウィンドウはブロックしない

J2SE 5.0までのモーダルは,Dialog.ModalityTypeではAPPLICATION_MODALに相当します。

一つのアプリケーションで複数のToolkitオブジェクトを使うことはほとんどないので,通常,モーダルとして使用されるのはAPPLICATION_MODALとDOCUMENT_MODALになります。

DOCUMENT_MODALを使用すれば,前述したヘルプ・ウィンドウの問題を解決できます。

さっそくこれをサンプルで確かめてみましょう。

サンプルのソースコード:ModalSample1.java

このサンプルは二つのフレームを生成し,それぞれにボタンがついています。ボタンをクリックするとダイアログが表示されます。

private void init(String title, int x, int y) {
    JFrame frame = new JFrame(title);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setBounds(x, y, 100, 75);

    JButton button = new JButton(title);
    frame.add(button);

    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            JButton source = (JButton)e.getSource();
            showDialog(source);
        }
    });

    frame.setVisible(true);
}

ダイアログを表示するshowDialogメソッドは次のようになります。

private void showDialog(JButton parent) {
    JOptionPane pane = new JOptionPane(parent.getText(),
                               JOptionPane.INFORMATION_MESSAGE);
         
    JDialog dialog = pane.createDialog(parent, parent.getText());

    // モーダルの設定
    dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);

    dialog.setVisible(true);
}

ここではJOptionPaneクラスを使用してダイアログを生成していますが,もちろん直接JDialogオブジェクトを生成してもかまいません。

新しいモーダルはDialog#setModalityTypeメソッドで設定します。

はじめはAPPLICATION_MODALで実行してみましょう。

APPLICATION_MODALでの実行
図1 APPLICATION_MODALでの実行

どちらか一方のダイアログが表示されていると,二つのフレームとも操作できません。これは今までのモーダルと同じ動作です。

それでは,モーダルをDOCUMENT_MODALに変更してみます。

private void showDialog(JButton parent) {
    JOptionPane pane = new JOptionPane(parent.getText(),
                               JOptionPane.INFORMATION_MESSAGE);

    JDialog dialog = pane.createDialog(parent, parent.getText());

    // モーダルの設定
    dialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL);

    dialog.setVisible(true);
}

DOCUMENT_MODALでの実行
図2 DOCUMENT_MODALでの実行

一方のフレームでダイアログを表示していても,他方のフレームは操作できます。とはいうものの,ダイアログの親となるフレームの操作はブロックされます。

ここではどちらのダイアログも同じモーダルを設定しましたが,異なるモーダルを設定することも可能です。

ところで,多くのダイアログを使用するアプリケーションでは,個々のダイアログにモーダルの設定をするのは面倒です。例えば,ヘルプ・ウィンドウだけはいつでも操作できるようにしたいというような場合は,ダイアログではなくウィンドウに設定を行うことができます。

つまり,ダイアログのモーダルの除外規則をウィンドウに設定します。このために,Dialog.ModalExclusionTypeというenumが導入されました。

Dialog.ModalExclusionTypeの取りうる値を表2に示します。

表2 Dialog.ModalExclusionType
説明
NO_EXCLUDE 除外しない(デフォルト)
APPLICATION_EXCLUDE APPLICATION_MODALなダイアログからのブロックを除外する
TOOLKIT_EXCLUDE APPLICATION_MODALもしくはTOOLKIT_MODALなダイアログからのブロックを除外する

この動作もサンプルで確認してみましょう。

サンプルのソースコード:ModalSample2.java

ModalExclusionTypeはWindow#setModalExclusionTypeメソッドで設定します。そこで,ModalSample2クラスでは片方のフレームにのみModalExclusionTypeを設定します。

public ModalSample2() {
    JFrame frame1 = init("Document 1", 200, 100);

    JFrame frame2 = init("Document 2", 500, 100);

    // frame2 のみ ModalExclusionType を設定する
    frame2.setModalExclusionType(
        Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
}

残りの部分はModalSample1とほぼ同一です。もちろん,ダイアログはAPPLICATION_MODALにしてあります。

実行すると,ダイアログが表示されていてもDocument 2のフレームは操作できます。自分の子供のダイアログに対しても,この除外規則は適用されるので,ダイアログをいくつも表示させることが可能になります。

ModalExculsionTypeの適用
図3 ModalExculsionTypeの適用

ダイアログは使用頻度も高いので,柔軟にモーダルを設定できるのはうれしいですね。

著者紹介 櫻庭祐一

横河電機 ネットワーク開発センタ所属。Java in the Box 主筆

今月の櫻庭

サン・マイクロシステムズとリクルートがタイアップして行っているMash up Award 2ndが開催されています。

昨年行われたMash up AwardではリクルートのWeb APIだけが対象でした。ところが,今回はサンとリクルート以外に,Skypeやシックスアパート,テクノラティなど協賛企業が17社もあります。使用できるWeb APIもバラエティに富んでいます。ということは,Mash upする材料がいろいろあるということ。アイデアしだいで,クールなアプリケーションが思いのままです。

締め切りは3月12日。何かおもしろいことをやってみたい方,ぜひトライしてみてくださいね。