ダイアログの使用

要約:
  • TAB キーとキーボード ショートカットを使用して、ダイアログ内のコントロール間を移動します。
  • ローカルおよび非ローカル オプションを使用してコントロールの外観を決めることができます。
  • コントロールを無効にできます。

移動

Curl® 言語で記述されたアプレット内では、ユーザーは TAB キーを使用してコントロールとリンクの間を移動することができます。また、SHIFT+TAB を使用して逆の向きに移動することもできます。
移動メカニズムは ActiveTraversor および ActiveTraversalContainer クラスによって実装されます。ActiveTraversor は、TAB を使って移動できるグラフィカル オブジェクトまたは可視オブジェクトで、ActiveTraversalContainer はそうしたオブジェクトのコンテナです。
ActiveTraversorActiveTraversalContainer は抽象クラスです。StandardActiveTraversorStandardActiveTraversalContainer は Curl が提供する具象クラスです。
もっとも一般的な ActiveTraversor はコントロールとリンクで、もっとも一般的な ActiveTraversalContainerDialog です。DialogActiveTraversor でもあることに注意してください。次の図では、クラス階層について説明しています。
ActiveTraversalContainer

StandardActiveTraversalContainer
GraphicOptions GuiEventTarget




ControlContainer


Dialog


移動は Dialog を介して行うのがもっとも一般的なので、機能の多くが ActiveTraversalContainer のすべてに共通するものであるとしても、このセクションの他の部分では移動を Dialog のために実装されたものとして説明します。
ユーザーが ActiveTraversor のタブをクリックすると、ActiveTraversoractive になります。アクティブな ActiveTraversor に必ずしもフォーカスがあるとは限りません。これは、Dialog.current-active プロパティの設定により、各 ActiveTraversalContainer がアクティブな ActiveTraversor を最高で 1 つ持つためです。ダイアログがフォーカスを取得すると、そのアクティブな ActiveTraversor もフォーカスを取得します。
たとえば、ユーザーが ALT-TAB で他のウィンドウに移動する場合、前のウインドウのアクティブな ActiveTraversor はフォーカスがないときでもアクティブなままです。そのウィンドウがフォーカスを再取得すると、その ActiveTraversor もフォーカスを再び取得します。
プログラムを使用して、ダイアログは ActiveTraversor.become-active を呼び出すことにより ActiveTraversor をアクティブにしようと試みます。 ActiveTraversor は可能であればアクティブになります。 コンテナの次または前の ActiveTraversor をアクティブ化させるには、ActiveTraversalContainer.traverse メソッドを使うことができます。 これらの両方のメソッドからは操作が成功したかを意味するブール値がリターンされます。 ActiveTraversor がアクティブにならない場合、その親を通して次の ActiveTraversor で試行します。
アクティブにならない ActiveTraversor (および通常、タブでスキップされる ActiveTraversor) は次の ActiveTraversor です。
ActiveTraversor は、その ActiveTraversalContainer に存在を通知し、ActiveTraversalContainerActiveTraversor を登録するようにするためのメカニズムとして非ローカル オプション active-traversal-container を使用します。
ダイアログはその最新の (登録済み) ActiveTraversor のリストを保持しています。ActiveTraversor のタブの順序は、各 ActiveTraversorActiveTraversor.tab-index 値によって変わります。既定では、tab-index0 の値を持っています。
ActiveTraversor は、タブ インデックス値が 0 であるものを除き、値を増加させるとタブが前に進みます。それらは最終のタブになります。同じインデックス値を持つ ActiveTraversor のタブは、親の定義した順序になります。たとえば、VBox 内では、トップレベル オブジェクトの既定のタブ順は (オブジェクトが同じタブ インデックスの場合) トップからボトムです。
明示的に ActiveTraversor のタブ順を設定し、ダイアログ内でのタブ順を変更することができます
ActiveTraversalContainer はそれ自体が ActiveTraversor なので、ActiveTraversalContainer 内のダイアログにもタブ インデックスがあります。
ローカル プロパティ Dialog.repeat-traversal? が TRUE の場合、タブの順序はダイアログの初めにループします。既定値が FALSE の場合、タブを移動すると親 ActiveTraversalContainer の次の ActiveTraversor へ進みます。

次の例では、コントロールとリンクのあるダイアログについて説明します。

例: ダイアログ内のコントロールとリンク
{let command:CommandButton={CommandButton}}
{let command2:CommandButton={CommandButton label="CommandButton2"}}
{let check:CheckButton={CheckButton}}
{let textf:TextField={TextField width=1in, prompt="TextField"}}

{set command.tab-index = 3}
{set command2.tab-index = 1}
{set textf.tab-index = 2}

{let dialog:Dialog=
    {Dialog
        repeat-traversal?=true,
        {spaced-hbox
            margin=0.25cm,
            command,
            command2,
            check,
            textf,
            {link href={url "dialogs-working.curl"}, Top of Page}
        }
    }
}
{let tfb:TextFlowBox = {TextFlowBox "Tab index values: "}}
{for control:Control in dialog.controls do
    {tfb.add control.tab-index}
    {tfb.add " "}
}

{VBox
    dialog, tfb
}
次の例では、GroupBox を使って、前例のコントロールをグループ化します。 tab を使ってコントロール間を移動します。 GroupBox 内のコントロールはフォーカスを取得しますが、 GroupBox 自体はフォーカスを受け取らないことに留意してください。 GroupBox.tab-index の値により、 Buttons とラベルの付くグループの前に、 Boxes とラベルの付くグループにナビゲートされることにも留意してください。

例: GroupBox を使ってコントロールをグループ化
{let command:CommandButton={CommandButton}}
{let command2:CommandButton={CommandButton label="CommandButton2"}}
{let check:CheckButton={CheckButton}}
{let textf:TextField={TextField width=1in, prompt="TextField"}}

{set command.tab-index = 3}
{set command2.tab-index = 1}
{set textf.tab-index = 2}

{Dialog
    repeat-traversal?=true,
    {spaced-hbox
        margin=0.25cm,
        {GroupBox
            label = "Buttons",
            tab-index = 5,
            {spaced-hbox
                command,
                command2
            }
        },
        {GroupBox
            label = "Boxes",
            tab-index = 4,
            {spaced-hbox
                check,
                textf
            }
        },
        {link href={url "dialogs-working.curl"}, Top of Page}
    }
}
ダイアログ内では、ユーザーはタブの順序で、ある Control から他へ移動することができます。たいていの場合、アクティブなコンポーネントはキーボード フォーカスを持っています。つまり、ユーザーが行うすべてのキーボードの動作は、その結果アクティブなコントロールで発生するイベントに変換されます。
次の例では、チェックボタンが become-active をそれ自身に呼び出すことによりプログラム的にアクティブになります。

例: コントロールをプログラム的にアクティブにする
{let textf:TextField={TextField prompt="TextField"}}
{let check:CheckButton={CheckButton}}

{let dialog:Dialog=
    {Dialog
        use-look-and-feel?=false,
        background = "wheat",
        {spaced-vbox
            margin=0.5cm,
            textf,
            check,
            {CommandButton
                label="Close",
                {on Action do
                    {dialog.close "closed"}
                }
            }
        },
        {on DialogShow at dialog:Dialog do
            {check.become-active}
        }
    }
}

{CommandButton
    {on Action do
        {dialog.show style="resizable"}
    }
}

コントロールのキーボード ショートカット

CommandButtonCheckButton、または RadioButton などのボタン コントロールは、通常はマウスでクリックします。しかし、ポイントとクリックの操作を置換できるキーボード ショートカットを使うユーザーも多くいます。
アクティブにしたいコントロールにキーを関連づける Control.mnemonic オプションを設定し、ボタンのショートカットを作成することができます。Alt-x のように、Alt キーと選択したニーモニックを押すことにより、ボタンのクリックをシミュレーションすることができます。
これらのキーボード ショートカットが機能するには、次の要求事項を満たしている必要があります。
次の例で、この機能について説明します。マウスを使ってダイアログ内のボタンの 1 つをクリックすると、Alt-xAlt-1Alt-V などを入力することにより、ボタン間を移動してチェックボタンをオン オフすることができます。
ここでは、ボタンラベルの文字に下線を付ける一般的な表記を使って、ユーザーにショートカットについて知らせています。Enter キーを押してコマンドボタンでポップアップしたダイアログを閉じることができます。

例: コントロールのキーボード ショートカット
{let rf:RadioFrame =
    {RadioFrame
        {spaced-vbox width=1.5in,
            {bold Radio Buttons},
            {RadioButton
                label = {text Radio Button {underline 1}},
                radio-value = "1",
                mnemonic = '1'},
            {RadioButton
                label = {text Radio Button {underline 2}},
                radio-value = "2",
                mnemonic = '2'},
            {RadioButton
                label = {text Radio Button {underline 3}},
                radio-value = "3",
                mnemonic = '3'}
        }
    },
    my-dialog:Dialog =
        {Dialog
            use-look-and-feel?=false,
            background = "wheat",
            margin = 0.25cm,
            {spaced-hbox
                {spaced-vbox width=1.5in,
                    {bold Check Buttons},
                    {CheckButton
                        label = {text {underline x}ylophone},
                        mnemonic = 'x',
                        width = 1.5in},
                    {CheckButton
                        label = {text {underline y}urt},
                        mnemonic = 'y',
                        width = 1.5in},
                    {CheckButton
                        label = {text {underline z}innia},
                        mnemonic = 'z',
                        width = 1.5in}
                },
                rf,
                {spaced-vbox
                    {bold Command Button},
                    {CommandButton
                        label = {text {underline V}alue of selected Radio Button},
                        mnemonic = 'V',
                        {on Action do
                            {popup-message
                                {spaced-vbox
                                    {format
                                        "RadioFrame's Value: %s", rf.value}
                                }
                            }
                        }
                    },
                   {Fill}
                }
            }
        }
}
{value my-dialog}
同様のキーの組合せがメニュー コマンドをアクティブにするキーボード ショートカットとして使用されていることもあるので注意してください。メニュー ショートカットがキーボード ショートカットに優先するので、メニュー ショートカットと競合しない文字を選択することが重要です。