リスト コントロール

概要

リスト コントロールではユーザーが値のリストから選択することができます。Curl API は以下のようなリスト コントロールを提供します。
リスト コントロールでは、使用可能な選択肢を ListItem 配列に格納しています。この配列には、読み取り専用のプロパティ ListModelControl.list-items でアクセスでき、このプロパティはリスト内のアイテムの反復子を返し、任意の配列のようにインデックスを付けることができます。リスト コントロールのアイテムの数は、ListModelControl.size プロパティにあります。リスト アイテムの値は、ListModelControl.list-item-creation-proc を使用して対応するリスト アイテムを作成し、ListModel として指定することができます。

リストの共通の特徴

この3つのタイプのリスト コントロールはすべて共通の構文と共通のプロパティを共有しています。次のセクション以降ですべてのリスト コントロールに共通の特徴を説明し、その後、それぞれのリスト コントロールについて詳細に説明します。

簡単なリスト

次の例では、ユーザーにテキスト文字列の短い、静的なリストを表示する簡単なリストを作成します。

例: 簡単なリスト
{ListBox
    height = 0.5in,
    "red", "green", "blue"
}
長いリストでは、ListSeparator を使用してアイテムをグループに分けることができます。

例: ListSeparator の付いた長いリスト
{ListBox
    height = 1.0in,
    "red", "green", "blue",
    {ListSeparator},
    "teal", "purple", "orange"
}

リスト アイテムの使用

ListValueItemListSeparator はスーパークラス ListItem のサブクラスです。ListValueItem オブジェクトはアイテムに item-valuelabel の両方を提供することができます。ListValueItem.enabled? プロパティでコントロールのアイテムが有効かどうかを制御します。有効でないアイテムは選択できません。
ListSeparator はユーザーが選択できないリスト アイテムですが、値を持っています。既定では、その値はハイフン ("-") 1文字の String です。この既定値を使ってリスト セパレーターを指定することできます。次の例の2番目のセパレーターがそれを示しています。
次の例では、ListValueItem を使ってリスト アイテムの体裁を制御します。このクラスはそれぞれのアイテムに値を設定し、ラベルを付けることができます。アイテム "purple" は無効になっています。有効にするにはコマンドボタンをクリックしてください。

例: 書式設定されたリスト アイテムの作成
{let lvi:ListValueItem = 
    {ListValueItem 
        "purple", 
        label = {text color = "purple", purple}, 
        enabled? = false
    }
}
{let lb:ListBox = 
    {ListBox
        {ListValueItem "red", label = {text color = "red", red}},
        {ListValueItem "green", label = {text color = "green", green}},
        {ListValueItem "blue", label = {text color = "blue", blue}},
        {ListSeparator},
        {ListValueItem "teal", label = {text color = "teal", teal}},
        lvi,
        {ListValueItem "orange", label = {text color = "orange", orange}},
        "-",
        {ListValueItem "gray", label = {text color = "gray", gray}},
        {ListValueItem "black", label = {text color = "black", black}}
    }
}
{VBox
    lb,
    {CommandButton
        label = "enable purple",
        {on Action do
            {set lvi.enabled? = true}
        }
    }
}
ListBoxDropdownList のコントロールでは値として何を使うか、またそれらをコントロールの中でどのように書式設定して使うかということに関して、かなり柔軟性があります。次の例では、テキスト文字列をリストの値として使用し、画像をそのラベルとして使用しています。

例: 画像としてのテキストの書式設定
{let lb:DropdownList = 
    {DropdownList
        value = "alpha",
        {ListValueItem 
            "alpha",
            label = {image source = {url "../../default/images/a-icon.gif"}}
        },
        {ListValueItem 
            "bravo",
            label = {image source = {url "../../default/images/b-icon.gif"}}
        },
        {ListValueItem 
            "charlie",
            label = {image source = {url "../../default/images/c-icon.gif"}}
        },
        {on ValueChanged at lb:DropdownList do
            {popup-message lb.value}
        }
    }
}
{value lb}
次の例では画像をリストの値として使用し、それらをテキストとして書式設定しています。

例: テキストとしての画像の書式設定
{let lb:DropdownList = 
    {DropdownList
        prompt = "select a word",
        {ListValueItem 
            {image source = {url "../../default/images/a-icon.gif"}}, 
            label = "alpha"
        },
        {ListValueItem 
            {image source = {url "../../default/images/b-icon.gif"}}, 
            label = "bravo"
        },
        {ListValueItem 
            {image source = {url "../../default/images/c-icon.gif"}}, 
            label = "charlie"
        },
        {on ValueChanged at lb:DropdownList do
            {popup-message lb.value}
        }
    }
}
{set lb.value = lb.data-model[0]}
{value lb}
アイテムのリストが長い場合、それぞれの ListValueItem を個別に作成するのは面倒で、またリスト アイテムがリストに動的に追加されている場合はとても厄介です。したがって、すべてのリスト コントロールで list-item-creation-proc プロパティを使って適切な引数にリスト アイテム(通常はラベルと値の両方)を返すプロシージャを指定することができます。
次の例では list-item-creation-proc をそれぞれのアイテムの書式を設定するプロシージャに設定します。プロシージャは色の名前の書式を設定するのでテキストは指定された色になります。またリスト セパレーターの指定に使われた値を処理し、ListSeparator を返します。リスト コントロールの作成後に追加されたアイテムの書式も設定されることに注意してください。

例: プロシージャを用いたリスト アイテムの書式設定
{let lb:ListBox = 
    {ListBox
        height = 1in,
        "red",
        "green",
        "blue",
        "-",
        "teal",
        "purple",
        "orange",
        list-item-creation-proc =
            {proc {val:any}:ListItem
                {if (val isa String) and (val == "-") then
                    {return
                        {ListSeparator}
                    }
                 else
                    {return
                        {ListValueItem 
                            val, 
                            label = {text color = val, 
                                      {value val}
                                  }
                        }
                    }
                }
            }
    }
}
{lb.append "cyan"}
{lb.append "magenta"}
{value lb}

リスト データ モデル

これまでのリスト コントロールの例ではコンストラクタの中での選択のリストについて示してきました。多くの場合、最良の設計の方法はリスト コントロールからそこで使われる値のリストを分離することです。たとえば、製品が入手可能な国のリストがあり、それがアプリケーション全体でいくつものコントロールで使用されているとします。リスト コントロールでは ListModel クラスを用いたこのレベルの抽象化をサポートし、これはあらゆるタイプの ListModelControl で使用することができます。ListModel を作成して、いくつものリスト コントロールの data-model プロパティの設定に使うことができます。
ListModel が提供するメソッドにより、モデル内での要素の追加、削除、変更が可能になります。 ListModel.controls-used-by プロパティはリスト モデルを使用したコントロールを記録します。リスト モデルはそのコンテンツが変更されたときにこれらのコントロールを通知します。
DefaultListModelListModel の具象サブクラスで、編集可能なリスト モデルを作成するためにインスタンス化することができます。抽象サブクラスである ReadOnlyListModel はリスト モデルのコンテンツを変更するすべての操作にエラーをスローします。これをモデル内のデータを変更から守るためのクラスの基本クラスとして使用できます。
次の例では ListModel を作成し、2つのリスト ボックス コントロールのデータ モデルとして使用します。ボタンをクリックすると、CommandButton のイベント ハンドラが ListModel にアイテムを追加し、両方のリスト コントロールは変更を反映するために更新されることに注目してください。

例: ListModel の使用
{let model:DefaultListModel  =
    {DefaultListModel
        "red", "green", "blue",
        "-",
        "teal", "purple", "orange"
    }
}
{HBox
    height = 3cm,
    valign = "top",
    {ListBox
        data-model = model,
        list-item-creation-proc =
            {proc {val:any}:ListItem
                {if (val isa String) and (val == "-") then
                    {return
                        {ListSeparator}
                    }
                 else
                    {return
                        {ListValueItem 
                            val, 
                            label = {text color =  val, {value val}}
                        }
                    }
                }
            }
    },
    {ListBox
        data-model = model
    },
    {CommandButton
        label = "add color",
        {on Action at cb:CommandButton do
            {model.append "cyan"}
        }
    }
}
リスト コントロールはデータ モデルを処理するためにスーパークラス ListModelControl から継承したメソッドを使用します。ほとんどの場合、これらのメソッドは ListModel 自体の対応するメソッドを呼び出すことによって実装されます。次のリストにはこれらのメソッド中でもっとも重要なものが含まれています。

リスト コントロールの値

リスト コントロールは ValueControl から継承するValue コントロールです。それぞれのリスト コントロールは値のプロパティを持ち、ユーザーはリストから1つまたは複数のアイテムを選択して設定することができます。リスト コントロールは、ほかのValue コントロールと値の処理の多くを共有しています。 「Value(値) コントロールのプロパティ」を参照してください。
リスト コントロールの主な使用目的は、ユーザーがコントロールとの直接的なやり取りを通して値を選択できるようにすることですが、リスト コントロールの値はプログラミングによって操作することもできます。次のリストにはプログラミングによってアイテムを選択したり、選択を解除したりする重要なメソッドが含まれています。
この例では ListBox ですべてのアイテムを選択する、または選択を解除するボタンを実装します。

例: アイテムの選択、または選択の解除
{let lb:ListBox = 
    {ListBox
        height = 0.8in,
        vorigin = "top",
        "Aardvark", "Cat", "Dog", "Elephant", "Gnu", "Zebra"
    }
}
{VBox
    {italic Select one or more options:},
    lb,
    {HBox
        {CommandButton
            label = "Select all",
            width = {add-stretch},
            {on Action at cb:CommandButton do
                {lb.select-all-items}
            }
        },
        {CommandButton
            label = "Deselect all",
            width = {add-stretch},
            {on Action at cb:CommandButton do
                {lb.deselect-all-items}
            }
        }
    }
}

リスト ボックス

ListBox は選択可能な値の縦方向のリストを表示します。リストのアイテムはテキストまたは画像で構成することができます。ユーザーは1つまたは複数のアイテムをリストから選択できます。リスト ボックスの値は現在選択されているすべてのリスト アイテムの値を含んだ配列です。
次の例では簡単なリスト ボックスを説明します。既定の ListBox.selection-policymultiple を使用するので、一度に複数のリスト アイテムを選択することができます。Shift キーを押しながら2つ目のアイテムをクリックすると、その間のアイテムがすべて選択されます。ValueFinished イベント ハンドラは value 配列のコンテンツを処理し、ポップアップ ダイアログで選択されたアイテムを表示します。この例では ListBoxStyle の既定である standard を使用します。

例: 簡単な ListBox
{let message:VBox = {VBox}}
{VBox
    {italic Select one or more of the following pets:},
    {ListBox
        height = 1.0in,
        "Aardvark", "Cat", "Dog", "Elephant", "Gnu", "Zebra",
        {on ValueFinished at lb:ListBox do
            {for x:any in lb.value do
                {message.add x}
            }
            {popup-message message}
            {message.clear}
        }
    }
}
次の例ではListBox.selection-policysingle に設定します。選択できるアイテムは1つに限られます。

例: 単一の選択をする ListBox
{let message:VBox = {VBox}}
{VBox
    {italic Select at most one of the following pets:},
    {ListBox
        selection-policy = "single",
        height = 1.0in,
        "Aardvark", "Cat", "Dog", "Elephant", "Gnu", "Zebra",
        {on ValueFinished at lb:ListBox do
            {for x:any in lb.value do
                {message.add x}
            }
            {popup-message message}
            {message.clear}
        }
    }
}
次の例で示す ListBox は複数の選択ができ、ポップアップ メッセージによって現在選択しているアイテムの数を教えてくれます。また stylecheckbutton ListBoxStyle に設定し、チェックボタンがそのアイテムが選択されているかどうかを表示します。既に選択されているアイテムをクリックすると、そのアイテムは選択されなくなるので注意してください。

例: checkbutton スタイルを使用した ListBox
{VBox
    {italic Select one or more options:},
    {ListBox
        style="checkbutton",
        height=0.8in,
        vorigin="top",
        "Moon roof", "Side air bags", "6-CD Changer", "Alarm System",
        {on ValueFinished at box:ListBox do
            {popup-message
                {text You have now selected  {value box.value.size} options.}
            }
        }
    }
}
次の例ではtoggle ListBoxStyle について説明します。このやり方は checkbutton と同じ機能を提供しますが、見た目には standard のやり方で使用されるのと同じです。リスト内のアイテムはクリックされると選択と非選択が切り替わります。

例: toggle スタイルを使用した ListBox
{VBox
    {italic Select one or more options:},
    {ListBox
        style="toggle",
        height=0.8in,
        vorigin="top",
        "Moon roof", "Side air bags", "6-CD Changer", "Alarm System",
        {on ValueFinished at box:ListBox do
            {popup-message
                {text You have now selected {value box.value.size} options.}
            }
        }
    }
}

ドロップダウン リスト

DropdownList はコントロールの現在値を表示し、コントロールが値を持たない場合は prompt を表示します。ユーザーは可能な値のリストを見るためにコントロール上をクリックしなければなりません。dropdown-height プロパティはリストの表示に使用する領域の高さを制御します。dropdown-height の既定値は 0pt で、リスト全体を表示するのに必要なだけの高さが使えます。高さがリスト全体を表示するのに十分でない場合は、ドロップダウン領域の右側に Scrollbar が表示されます。
ユーザーは通常、アイテムをポイントしてクリックすることによりエントリを 1 つだけ選択することができます。選択されたアイテムは、リストにあったときに表示されていたように、可視フィールドに表示されます。ラベルがグラフィック オブジェクトまたはある種のテキストであれば、選択されたアイテムの値またはラベルはどんなタイプでも可能です。
プロンプトが指定されており、初期値が選択されていない DropdownList の例を次に示します。

例: 州のドロップダウン リスト
{let list-of-states:DefaultListModel =
    {DefaultListModel
        "Alabama", "Alaska", "Arizona", "Arkansas", "California",
        "Colorado", "Connecticut", "Delaware", "Florida", "Georgia",
        "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa",
        "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland",
        "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri",
        "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey",
        "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio",
        "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina",
        "South Dakota", "Tennessee", "Texas", "Utah", "Vermont",
        "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"
    }
}
{DropdownList
    prompt = "Choose a state:",
    data-model = list-of-states,
    dropdown-height = 2in,
    {on ValueFinished at ddl:DropdownList do
        {popup-message
            {text You have chosen the state of {value ddl.value}.}
        }
    }
}

色のドロップダウン リスト

ColorDropdown クラスは DropdownList のサブクラスで色の選択に特化しています。色の名前のリストを色づけされた四角形で表示します。
ColorDropdown.color-array プロパティを使用して色を表す文字列の配列を指定します。色のリストを指定しない場合、コントロールは既定の12色の設定を使用します。コントロールの作成後に color-array を変更することはできません。
initial-color プロパティはコントロールの初期値を設定し、コントロールが最初に表示する色を決定します。no-color-value プロパティはコントロールのリスト アイテムとして表示される文字列を提供し、ユーザーは色を選択しないことが可能です。色の選択をしないとユーザーに既定の色を使わせるのに便利です。
次の例では、最初の ColorDropdown では既定の色のセットを使用し、最初の色を指定します。2番目では色の配列を指定し、色の値は指定しません。2番目の色のドロップダウンでは既定の境界色に戻ることができますが、最初のものではできないことに注目してください。

例: 色のドロップダウン リスト
{spaced-hbox
    valign = "center",
    {ColorDropdown
        width = 1in,
        border-width = 2pt,
        initial-color = "green",
        {on ValueFinished at c:ColorDropdown do
            set c.border-color = c.value
        }
    },
    {ColorDropdown
        width = 1in,
        border-width = 2pt,
        no-color-value = "",
        color-array = {StringArray "pink", "cyan", "teal"},
        {on ValueFinished at c:ColorDropdown do
            {if c.value == "" then
                {unset-option-by-name c, "border-color"}
             else
                set c.border-color = c.value
            }
        }
    }
}

コンボ ボックス

ComboBox は、次の結合されたフォームにエントリのリストを表示します。
ユーザーはリスト内のエントリの1つを選択することも、テキスト フィールドに値を入力することもできます。ComboBox のテキスト フィールドの部分はテキストの入力に使われるので、ユーザーは矢印ボタンをクリックして可能な値のリストを表示させなければなりません。ComboBoxDropdownList はともに dropdown-height プロパティを使用して、リストの表示に使用する領域の高さを制御します。
次の例では ComboBox を作成し、インスタンス化の間にリストの要素を指定します。ComboBox.value を設定することによりコンボ ボックスが最初に表示するエントリを指定することに注目してください。

例: 簡単な ComboBox
{ComboBox
    value = "Yangtze",
    "Nile",
    "Amazon",
    "Yangtze",
    "Mississippi",
    "Yenisei"
}
初期値を設定せず、プロンプトを設定することもできます。
ユーザーは ComboBox に値を入力できるので、可能な値は文字列に限られます。選択可能な値のリスト内で文字列を書式設定することができますが、アイテムが選択されるとそのコントロールで実行中のテキスト フォーマットにレンダリングされます。
次の例のリストの要素はドロップダウン リストで見るときの list-item-creation-proc で指定された色です。要素を選択するとコントロールを含む Frame で指定された色になります。

例: ComboBox の値が文字列の場合
{let model:DefaultListModel =
    {DefaultListModel
        "red", "green", "blue",
        "-",
        "teal", "purple", "orange"
    }
}
{Frame
    color = "black",
    {ComboBox
        control-appearance-changeable? = true,
        data-model = model,
        list-item-creation-proc =
            {proc {val:any}:ListItem
                {if val == "-" then
                    {return
                        {ListSeparator}
                    }
                 else
                    {return
                        {ListValueItem 
                            val, 
                            label = {text color = val, {value val}}
                        }
                    }
                }
            }
    }
}
max-chars プロパティはユーザーがテキスト フィールドに入力できる文字数を制限します。次の例ではテキストの入力を、米国の郵便用州略号の表示に使用する2文字に制限しています。

例: 入力の長さを制限する max-chars の使用
{ComboBox
    prompt = "state",
    max-chars = 2,
    "CT",
    "MA",
    "ME",
    "NH",
    "RI",
    "VT"
}
ComboBox.value プロパティは、現在選択されているエントリの値を保持します。ユーザーが ComboBox と対話しているとき、次のイベントが発生します。
次の例では ValueFinished イベント発生時に favorite の値をコンボ ボックスの現在値に設定する ComboBox を説明します。

例: Actionイベント ハンドラ付きの ComboBox
{value
    let favorite:Dynamic =
        {Dynamic
            {text init}
        }
    let combi:ComboBox =
        {ComboBox
            {on ValueFinished at combo:ComboBox do
                || 動的な変数(favorite) を更新します。
                set favorite.value = combo.value
            }
        }

    {combi.append "8pt"}
    {combi.append "10pt"}
    {combi.append "18pt"}
    {combi.append "24pt"}
    {combi.append "28pt"}

    || ComboBox を初期化します。
    set combi.value = "10pt"
    set favorite.value = combi.value


    {Dialog
        {spaced-vbox halign = "center",
            {paragraph Select your favorite font size:},
            combi,
            {CommandButton label = "Show font size",
                {on Action do
                    let your-size:Distance = {combi.value.to-int}*1pt
                    {if your-size < 5pt or your-size > 40pt then
                        {popup-message title = "Bad font size",
                            {text Please choose a better font size.}


                        }
                     else
                        {popup-message
                            title = "Your font size",
                            {text
                                font-size = your-size,
                                An example of your favorite font size!
                            }
                        }
                    }
                }
            },
            {text
                font-family = "sans-serif",
                font-weight = "bold",
                Your favorite font size is {value favorite}.
            }
        }
    }
}