SpinControl を使用すると、一連の値から 1 つの値を表示し選択することができます。特に、昇順または降順に自然にソートされる値セットを使用する場合に特に便利なコントロールです。上向き矢印または下向き矢印をクリックするか、キーボードの上方向キーまたは下方向キーを押して、現在より高い値や低い値を選択できます。
例:
単純な
SpinControl |
|
{SpinControl
domain =
{StandardIntDomain
default-value = 0,
min-allowable = -10,
max-allowable = 10
}
}
| |
SpinControl.step プロパティは、ドメイン内の次の値までの増分を制御します。このコントロールは現在値を
step の値だけ増加させます。既定値は整数の 1 です。
次の例では、step を 5 に設定します。上向き矢印をクリックして値が 0 から 5 に変わることに注目してください。キーボードを使用して値を編集すると、コントロールはその新しい値から 5 ずつ増加させます。
例:
step が 5 の場合 |
|
{SpinControl
domain =
{StandardIntDomain
default-value = 0,
min-allowable = -100,
max-allowable = 100
},
step = 5
}
| |
SpinControl.editable? プロパティーとともに step を使用すると、使用可能なすべての値をリストしなくても、使用可能な値を制限できます。次の例では、
step を 5 に、
editable? を
false に設定します。この組み合わせは値の選択肢を -100 から 100までの 5 の倍数に制限します。
例:
値を 5 の倍数に制限 |
|
{SpinControl
domain =
{StandardIntDomain
default-value = 0,
min-allowable = -100,
max-allowable = 100
},
editable? = false,
step = 5
}
| |
このコントロールでは、0 秒から 12 時までの時間値はすべて有効です。step プロパティでは、増分として 15 分を指定しています。ただし、step は使用可能な値は制限していません。コントロールを編集して、指定の範囲内で有効な時間値を入力できます。
例:
Time による SpinControl の使用 |
|
{SpinControl
width = 3cm,
domain =
{StandardTimeDomain
default-value = 0s,
min-allowable = 0s,
max-allowable = 12h
},
step = 15min
}
| |
SpinControl.wrap? プロパティは、最大値または最小値に達したときのコントロールの動作を制御します。
wrap? が
true の場合は、最大値または最小値を超えて、逆の限界値に折り返します。既定値は
false です。
スピン コントロールを使用して、月の日付を選択する例を次に示します。wrap? を true に設定しているため、コントロールは 1 から 31 に進み、31 に到達すると 1 に戻ります。
例:
wrap? の使用 |
|
{SpinControl
domain =
{StandardIntDomain
default-value = 1,
min-allowable = 1,
max-allowable = 31
},
wrap? = true
}
| |
列挙型によって指定された値はソートされないので、列挙型を使用して値セットを特定の順序に指定することができます。
次の例は、曜日を含む列挙型を指定します。これらの値は、ソート順ではなく、曜日順に表示する必要があります。ユーザーはコントロール値を直接編集できますが、いずれかの有効な値に正確に一致する文字列を入力する必要があります。たとえば、
Friday は有効な入力値ですが、
friday は無効です。
friday を有効な入力とするには、
parse-spec を指定する必要があります。「
解析と書式設定」を参照してください。
editable? プロパティを
false に設定すると、ユーザー入力を無効にできます。
例:
SpinControl での列挙型の使用 |
|
{define-enum public Days
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
{SpinControl
width = 3cm,
|| 以下のコメントをはずすと編集ができなくなります。
||-- editable? = false,
domain =
{Domain.from-type
Days
}
}
| |
場合によっては、列挙型を使用して得られる以上の柔軟性が必要かもしれません。たとえば、コントロールで使用可能な値が、ユーザーの行った選択によって決定される場合などです。そのような状況では、配列へのインデックス値としてスピン コントロール内で整数の値を使用することができます。その後、配列の中身を動的に決定することができます。スピン コントロールを使用して配列から対応する値を取得する format-spec を作成する必要があります。format-spec は配列から文字列を取得できなければなりません。format-spec がスピン コントロールのテキスト表示フィールドで使用される値を指定するからです。
整数を使用して文字列の配列のインデックスをつけることはもっとも簡単な方法です。この方法は、文字列を他の型のオブジェクトに関連付けるような、より複雑なオブジェクトの配列にも使用できます。
次の例でこの方法を説明します。スピン コントロールで 2 セットの値から選択します。これらの値は2つの配列によって指定されています。月曜から金曜までの曜日名を持つ weekdays または、土曜と日曜の名前を持つ weekend です。
array-spinner プロシージャは
StringArray の値に特化された
SpinControl を作成します。コントロールを作成する際に配列を指定します。コンストラクタは配列を使用して使用可能な整数の最大値を設定し、整数値を文字列としてフォーマットします。プロシージャの残余引数で
SpinControl への追加引数を指定することができます。残余引数の使用についての詳細は「
引数」を参照してください。
spin-over-array プロシージャは
array-spinner で作成されたコントロールを特定の文字列配列に関連付けます。
week-spinner コントロールは
array-spinner を使用して用例の表示で表示されるコントロールを作成します。このコントロールは
TextDisplay のコンテンツを更新し、配列から整数値とそれに対応する文字列を取得し表示します。これによりコントロールの現在値を見ることができます。
それぞれの
CommandButton は
week-spinner で使用された配列を
weekend または
weekday に設定します。
例:
配列のインデックス作成への SpinControl の使用 |
|
{let weekdays:{Array-of String} =
{{Array-of String}
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday"
}
}
{let weekend:{Array-of String} =
{{Array-of String}
"Saturday",
"Sunday"
}
}
{define-proc {array-spinner a:StringArray, ...}:SpinControl
{return
{SpinControl {splice ...},
domain =
{StandardIntDomain
default-value = 0,
min-allowable = 0,
max-allowable = a.size - 1
},
format-spec =
{proc {data:any, sp:SpinControl}:String
{return a[data asa int]}
}
}
}
}
{define-proc {spin-over-array a:StringArray, sp:SpinControl}:void
set sp.value = 0
set sp.domain =
{StandardIntDomain
default-value = 0,
min-allowable = 0,
max-allowable = a.size - 1
}
set sp.format-spec =
{proc {data:any, sp:SpinControl}:String
{return a[data asa int]}
}
{sp.set-value-with-events 0}
}
{let display:TextDisplay = {TextDisplay}}
{let week-spinner:SpinControl =
{array-spinner
weekdays,
width = 4cm,
wrap? = true,
{on ValueFinished at sp:SpinControl do
set display.value =
{type-switch sp.format-spec
case str:String do
{format str, sp.value}
case proc:{proc-type {any, SpinControl}:String} do
{format "%s %s", sp.value, {proc sp.value, sp}}
else
{format "%s", sp.value}
}
}
}
}
{Dialog
margin = 3pt,
{VBox
spacing = 2pt,
week-spinner,
{HBox
"Value =\ ",
display
},
{HBox
{CommandButton
width = {make-elastic},
label = "Weekend",
{on Action do
{spin-over-array weekend, week-spinner}
}
},
{CommandButton
width = {make-elastic},
label = "Weekday",
{on Action do
{spin-over-array weekdays, week-spinner}
}
}
}
}
}
| |
- format-spec プロパティは、コントロール値を文字列にフォーマットして表示する方法を決定します。値が null の場合、コントロールは関連付けられているドメインの Domain.format メソッドを使用します。
- parse-spec プロパティは、ユーザーがコントロールで入力した文字列を、コントロールでどのように処理するかを決定します。値が null の場合、コントロールは関連付けられているドメインの Domain.parse メソッドを使用します。
次の例では、16 進形式の整数値を解析してフォーマットします。
format-spec は、format マクロに適した文字列です。
parse-spec は
hex-parse というプロシージャで、文字列入力を 16 進数として解釈します。文字列が有効な入力でない場合、
parse-spec が
ValidationException をスローしてコントロールに有効な入力でないことを表示します。コントロールは値を変更しません。
例:
format-spec および parse-spec の使用 |
|
{define-proc package {hex-parse
str:String,
sp:SpinControl
}:any
let (new-value:int, n-chars-consumed:int, overflow?:bool) =
{str.to-int radix = 16, error-if-overflow? = false}
{if not overflow? and
new-value >= (sp.min-value asa int) and
new-value <= (sp.max-value asa int)
then
{return new-value}
}
{throw
{ValidationException "Not a Valid Value"}
}
}
{SpinControl
width = 3cm,
domain =
{StandardIntDomain
default-value = 0,
min-allowable = 0,
max-allowable = 255
},
font-size = 18pt,
format-spec = "%0X",
parse-spec = hex-parse
}
| |
SpinControl には、次のメソッドが用意されています。これらのメソッドを使用すると、ユーザーによるコントロールの操作をプログラムでシミュレーションできます。
例:
プログラムによる SpinControl の操作 |
|
{let arr:{Array-of int} = {{Array-of int} 20, 50, 30, 10, 40}}
{let spin-one:SpinControl =
{SpinControl
|| 以下のコメントをはずすとイベントが確認できます。
||-- {on e:ValueFinished at x:SpinControl do
||-- {popup-message x.value}
||-- },
domain =
{StandardIntDomain
default-value = 30,
allowable-values = arr
}
}
}
{let spin-two:SpinControl =
{SpinControl
|| 以下のコメントをはずすとイベントが確認できます。
||-- {on e:ValueFinished at x:SpinControl do
||-- {popup-message x.value}
||-- },
domain =
{StandardIntDomain
default-value = 50,
min-allowable = 0,
max-allowable = 100
}
}
}
{VBox
spin-one,
spin-two,
{HBox
{CommandButton
label = "set to default values",
{on Action do
{spin-one.set-value-with-events spin-one.domain.default-value}
{spin-two.set-value-with-events spin-one.domain.default-value}
}
}
}
}
| |
CalendarControl を使用すると、グラフィカルなカレンダーから日付を選択できます。単純な
CalendarControl の例を次に示します。コントロールでは現在の月と年が表示され、現在の日付は、数字を含む長方形の背景色で示されています。このコントロールには、初期値は設定されていません。数字をクリックして日付を選択すると、コントロール値が設定されます。選択した日付の周囲に色付きの境界線が引かれ、現在の値が示されます。
上部にある 2 つのスピン コントロールを使用して、表示する年と月を切り替えることができます。
例:
単純な CalendarControl |
|
{CalendarControl}
| |
これらのオプションを変更した結果を次の例に示します。
例:
CalendarControl の色の設定 |
|
{CalendarControl
calendar-control-header-background = "#cceecc",
calendar-control-selected-day-color = "red",
calendar-control-today-background = "#cceecc"
}
| |
次のブール値オプションを使用して、表示する情報を追加したり削除したりできます。
これらのオプションの値を変更した結果を次の例に示します。
例:
CalendarControl による表示情報の変更 |
|
{CalendarControl
show-week-of-year? = true,
show-adjacent-dates? = true,
show-date-controls? = false
}
| |
例:
CalendarControl と関連イベント |
|
{let changed-value:TextField = {TextField}}
{let finished-value:TextField = {TextField}}
{let cc:CalendarControl =
{CalendarControl
{on ValueChanged at s:CalendarControl do
set changed-value.value = {String s.value.info.locale-date}
},
{on ValueFinished at s:CalendarControl do
set finished-value.value = {String s.value.info.locale-date}
}
}
}
{VBox
cc,
{Table
{row-prototype "Changed value: ", {value changed-value}},
{row-prototype "Finished value: ", {value finished-value}}
},
{CommandButton
label = "unset data field",
{on Action do
{cc.unset-value}
}
}
}
| |
次の例では、data-model によって最大値と最小値、およびコントロールの初期値が設定されます。データ モデルを削除して例を実行すると、コントロールに初期値が設定されていないことがわかります。
例:
データ モデルの使用 |
|
{let cc:CalendarControl =
{CalendarControl
data-model =
{DateDataModel
{DateTime "01/01/2006"},
{DateTime "12/31/2006"},
{DateTime "12/15/2006"}
}
}
}
{VBox
cc,
{if cc.has-value? then
{spaced-hbox "Initial value is: ",
cc.value.info.locale-date
}
else
"No initial value."
}
}
| |
例:
データモデルの変更 |
|
{let fall:DateDataModel =
{DateDataModel
{DateTime "09/01/2006"},
{DateTime "01/31/2007"},
{DateTime "09/15/2006"}
}
}
{let spring:DateDataModel =
{DateDataModel
{DateTime "02/01/2007"},
{DateTime "06/30/2007"},
{DateTime "02/15/2007"}
}
}
{let calendar-control:CalendarControl =
{CalendarControl
data-model = fall
}
}
{Dialog
{VBox
{text Select a date:},
{RadioFrame
value = 0,
{HBox
{text Term:},
{Fill},
{RadioButton
label = "Fall 2006",
radio-value = 0
},
{RadioButton
label = "Spring 2007",
radio-value = 1
}
},
{on ValueChanged at rf:RadioFrame do
{if rf.value == 0 then
set calendar-control.data-model = fall
else
set calendar-control.data-model = spring
}
}
},
calendar-control
}
}
| |
例:
データ モデルの範囲の設定 |
|
{let calendar-control:CalendarControl =
{CalendarControl
data-model =
{DateDataModel
{DateTime "01/01/2006"},
{DateTime "12/31/2006"},
{DateTime "12/01/2006"}
}
}
}
{VBox
calendar-control,
{CommandButton
width = {add-stretch},
label = "Change data model range",
{on Action do
{calendar-control.data-model.set-range
{DateTime "12/01/2006"},
{DateTime "12/31/2006"}
}
}
}
}
| |
{calendar-control.note-holidays-changed}
コマンド ボタンをクリックしても、追加の休日が表示されないことに注意してください。
例:
休日のリストの指定 |
|
{let holiday-list:{Array-of DateTime} =
{new {Array-of DateTime},
{DateTime "01/02/2006"},
{DateTime "01/03/2006"},
{DateTime "01/04/2006"},
{DateTime "01/05/2006"},
{DateTime "01/06/2006"}
}
}
{let calendar-control:CalendarControl =
{CalendarControl
data-model =
{DateDataModel
{DateTime "01/01/2006"},
{DateTime "12/31/2006"},
{DateTime "01/31/2006"}
},
holidays = holiday-list
}
}
{VBox
calendar-control,
{CommandButton
label = "Add more holidays",
width = {add-stretch},
{on Action do
{for d:DateTime in holiday-list do
set d = d + 7d
{holiday-list.append d}
}
{calendar-control.note-holidays-changed}
set calendar-control.calendar-control-holiday-background = "beige"
set calendar-control.calendar-control-holiday-color = "brown"
}
}
}
| |
既定では、
CalendarControl は週の見出しで
short-weekday-names の名前を使用し、月の選択に使用するスピン コントロールで
month-names の名前を使用します。
例:
weekday-proc の指定 |
|
{CalendarControl
data-model =
{DateDataModel
{DateTime "01/01/2006"},
{DateTime "12/31/2006"},
{DateTime "12/01/2006"}
},
weekday-proc =
{proc {cc:CalendarControl, weekday:int}:(#Graphic)
{return
cc.weekday-names[weekday - 1]
}
}
}
| |
- 関連付けられている CalendarControl : DateField の右側のアイコンをクリックすると、ドロップダウン カレンダー コントロールが表示されます。このコントロールを使用すると、CalendarControl のすべての機能を DateField で使用できます。「カレンダー コントロール」を参照してください。
- 初期値なし : DateField には初期値が設定されていません。ただし、DateField の value プロパティで設定した場合を除きます。
- 日付入力の検証 : テキスト入力フィールドに値を入力できますが、コントロールが日付として解釈できる文字列を入力する必要があります。その他の文字列を入力しても機能しません。テキスト フィールドまたはカレンダー コントロールを使用して、有効な日付を入力してください。フィールドに有効な値が入力された場合にのみ、日付フィールドの他の機能が使用できるようになります。
- 日付選択用の SpinControl : DateField には、日付専用のスピン コントロール機能があります。現在より高い値や低い値を選択すると、カーソルが置かれている日付に対応するインターバル分だけ、日付が変わります。日付の日の部分をクリックし、上方向キーや下方向キーを押すと、1 日ずつ日数が増減することに注意してください。同様に、月または年をクリックして上方向キーや下方向キーを押すと、日付が 1 日分または 1 ヶ月分ずつ変わります。
例:
単純な DateField |
|
{DateField}
| |
例:
プロンプトとスピン ボタン付きの DateField |
|
{let df:DateField =
{DateField
prompt = "",
show-spin-buttons? = true
}
}
{HBox
df,
{CommandButton
label = "unset data field",
{on Action do
{df.unset-value}
}
}
}
| |
例:
データ モデルの変更 |
|
{let cal-control:CalendarControl =
{CalendarControl
takes-focus? = false,
data-model =
{DateDataModel
{DateTime "01/01/2006"},
{DateTime "12/31/2006"},
{DateTime "12/25/2006"}
}
}
}
{let cc-date-field:DateField =
{DateField
prompt = "",
calendar-control = cal-control
}
}
{spaced-vbox
{HBox
cc-date-field,
{CommandButton
label = "change data model",
{on Action do
set cal-control.data-model =
{DateDataModel
{DateTime "01/01/2005"},
{DateTime "12/31/2006"},
{DateTime "12/25/2005"}
}
{cc-date-field.note-calendar-control-property-changed}
}
}
}
}
| |
ProgressBar は、アプリケーションで時間のかかるタスクを実行し、エンド ユーザーにそのタスクの進捗状況を知らせる必要がある場合に使用します。単純にアプリケーションがビジー状態であることを示す待機カーソルよりも詳しい情報を表示します。
ProgressBar では、処理の進行速度と処理がどの程度完了しているかがわかります。
次の例は、
ProgressBar の単純な使用法を示しています。[
Start] を押すと、
sleep を使用してアプレットによる処理をシミュレーションする計算ループに入り、
ProgressBar を更新します。アプレットがビジー状態でプログレスバーが実行されている間に待機カーソルを表示するのもよい方法です。
アプレットが長時間ビジー状態の場合は、UI を無効にするのは良い方法です。 UI を無効にしない場合は、アプレットがビジー状態の間にキューに格納されたすべてのイベントは、長い計算が完了すると処理されます。プログレスバーの実行中に Show Popup ボタンを数回クリックしてください。計算ループが終了するまでポップアップ メッセージが表示されないことと、終了時にすべてのメッセージが一度に表示されることに注意してください。
コードのコメント化された行のコメントを解除して例を実行すると、アプレットがビジー状態の間 UI を無効にする効果が得られます。UI を再度有効にするコードを {after 0s do} ブロック内に入力することで、UI が無効な状態のままでアプレットが処理中でビジー状態の間に、イベントを蓄積することができます。
また、アプレットが逼迫した計算ループに入ると、画面更新イベントなどのイベントが処理されないことにも注意してください。アプレットで画面が確実に更新されるようにするには、ここで示すように
ProgressBar.update-view を呼び出します。
例:
スタート ボタンを持つ単純なプログレスバー |
|
{let max:double = 700}
{let simple-bar:ProgressBar =
{ProgressBar
width = 5cm,
min-value = 0,
max-value = max,
value = 0,
caption = "Press Start to Begin",
{on e:ValueChanged at pb:ProgressBar do
set pb.caption = pb.percent-complete & "%"
{pb.update-view}
}
}
}
{HBox
"Progress:",
simple-bar,
{CommandButton
label = "Start",
{on Action at cb:CommandButton do
||-- 以下のコメントをはずすと UI が無効になります。
||-- let view = {cb.get-view}
||-- {if-non-null view then
||-- set view.enabled? = false
||-- }
{with-busy-cursor
{for i = 1.0 to max do
{simple-bar.set-value-with-events i}
|| 待機時間を作ります。
{sleep .01s}
}
}
||-- 以下のコメントをはずすと再び UI が有効になります。
||-- {after 0s do
||-- {if-non-null view then
||-- set view.enabled? = true
||-- }
||-- }
}
},
{CommandButton
label = "Show Popup",
{on Action do
{popup-message "Message"}
}
}
}
| |
次の例は
Cancel ボタンを追加します。計算ループ内で
dispatch-events を呼び出して、アプレットが
Cancel ボタンに反応して計算ループを終了できるようにしています。
実際のアプリケーションで
Cancel ボタンを持つ
ProgressBar を使用するには、プログレスバーと UI を更新するコードを、時間を消費する処理を行うルーチンに追加します。ユーザー インターフェイスは
dispatch-events が呼び出される場合にのみアクティブになります。この例では、このプロシージャはループを回るごとに 1 回呼び出されます。実際のアプリケーションでは、1 回の繰り返しが遅くなると、ユーザーはアプレットが反応していないことに気付く場合があります。
この例では、時間を消費する処理が実行されている間、不必要な再入を避けるために残りのユーザー インターフェイスを無効にします。
dispatch-events を呼び出すたびに、すべての着信イベントが処理されます。UI が有効の場合、アプレットは現在の操作が完了する前に他の操作を行おうとする場合があります。
Cancel ボタンに明示的に
enabled? = true を設定して、収容している
View が無効な場合にこのボタンが無効にならないようにする必要があります。
[Start working] というラベルのボタンをクリックして、例が含まれているダイアログを表示してください。この例は、別個のダイアログによって実装されるため、UI を無効にするコードによって、このドキュメントを表示するアプレット全体の UI が無効になることはありません。
例:
スタート ボタンとキャンセル ボタンを持つ単純なプログレスバー |
|
{let max:double = 1000}
{let computing?:bool = false}
{let pb:ProgressBar =
{ProgressBar
width = 5cm,
enabled? = true,
min-value = 0,
max-value = max,
value = 0,
caption = "Press Start to Begin",
{on e:ValueChanged at pb:ProgressBar do
set pb.caption = pb.percent-complete & "%"
}
}
}
{let d:Dialog =
{Dialog
{HBox
"Progress:",
pb,
{CommandButton
label = "Start",
{on Action at cb:CommandButton do
set computing? = true
{if-non-null view = {cb.get-view} then
set view.enabled? = false
}
{for i = 1.0 to max do
{pb.set-value-with-events i}
|| これは待機時間を作ります。
{sleep .01s}
{dispatch-events false}
{if not computing? then
set pb.caption = "Canceled. Press Start to begin."
{break}
}
}
{if-non-null view = {cb.get-view} then
set view.enabled? = true
}
}
},
{CommandButton
label = "Cancel",
enabled? = true, || [Cancel] ボタンは有効でなければいけません。
{on Action do
set computing? = false
{pb.set-value-with-events 0.0}
}
},
{CommandButton
label = "Show Popup",
{on Action do
{popup-message "Message"}
}
}
}
}
}
{CommandButton
label = "Start working.",
{on Action do
{d.show}
}
}
| |
次の例は以前の例とは異なるアプレット構造を使います。
呼び出す毎に少しずつ処理を進めることのできるルーチンにより、時間を消費する処理は実行されます。
この構造により[pause]ボタンを追加することができるため、エンドユーザーは処理を中断し、
他の操作を行い、後にこの処理を再開することができます。
この例では、compute と呼ばれるプロシージャが、
長い全処理の一部を実行するルーチンをシミュレートします。
ループは compute を繰り返し呼び出します。
この例では、UI を計算コードから分離するという適切な処理を行っていますが、
繰り返し呼び出して処理を実行できるプロシージャまたはメソッドが必要となります。
例:
スタート ボタンと一時停止ボタンを持つプログレスバー |
|
{let max:double = 50}
{let computing?:bool = false}
{let so-far:double = 0}
{define-proc {compute}:void
{for j = 1 to 1000000 do
{let x:double = {sqrt 3}}
}
}
{let prog-bar:ProgressBar =
{ProgressBar
width = 5cm,
enabled? = true,
min-value = 0,
max-value = max,
value = 0,
caption = "Press Start to Begin",
progress-color =
{LinearGradientFillPattern
{Fraction2d 0, 1},
{Fraction2d 0, 0},
{Spectrum.from-envelope
{FillPattern.get-silver}, 0,
{FillPattern.get-white}, 0.5,
{FillPattern.get-silver}, 1.0
}
},
{on e:ValueChanged at pb:ProgressBar do
set pb.caption = pb.percent-complete & "%"
}
}
}
{let d:Dialog =
{Dialog
{HBox
"Progress:",
prog-bar,
{CommandButton
label = "Start",
{on Action at cb:CommandButton do
set computing? = true
{if-non-null view = {cb.get-view} then
set view.enabled? = false
}
{for i = so-far to max do
{prog-bar.set-value-with-events i}
{compute}
set so-far = i
{dispatch-events false}
{if not computing? then
set prog-bar.caption =
"Paused. Press Start to resume."
{break}
}
}
{if-non-null view = {cb.get-view} then
set view.enabled? = true
}
}
},
{CommandButton
label = "Pause",
enabled? = true,
{on Action do
set computing? = false
}
}
}
}
}
{CommandButton
label = "Start working.",
{on Action do
{d.show}
}
}
| |
次の例は、不確定プログレスバーを示しています。
コードの構造は前の例と同じで、compute ルーチンは繰り返し呼び出されます。
例:
スタート ボタンと終了ボタンを持つ不確定プログレスバー |
|
{define-proc {compute}:void
{for j = 1 to 1000000 do
{let x:double = {sqrt 3}}
}
}
{let computing?:bool = false}
{let pb:ProgressBar =
{ProgressBar
width = 5cm,
caption = "Press Start to Begin",
progress-color = "#5BDD5D"
}
}
{let rr:RolledRandom = {RolledRandom 50, 150}}
{let d:Dialog =
{Dialog
{HBox
"Progress:",
pb,
{CommandButton
label = "Start",
{on Action at cb:CommandButton do
set computing? = true
set pb.indeterminate? = true
{if-non-null view = {cb.get-view} then
set view.enabled? = false
}
{for i = 1.0 to {rr.next-roll} do
{if computing? then
set pb.caption = ""
{compute}
{dispatch-events false}
else
set pb.caption =
"Stopped. Press Start to begin."
{break}
}
}
set pb.indeterminate? = false
{if-non-null view = {cb.get-view} then
set view.enabled? = true
}
}
},
{CommandButton
label = "Stop",
enabled? = true,
{on Action do
set computing? = false
}
}
}
}
}
{CommandButton
label = "Start working.",
{on Action do
{d.show}
}
}
| |
Slider では、定義済みの値コレクションから値または値の範囲を選択できます。値をソート順に表示するという点で
SpinControl に似ています。スライダのつまみを移動して値を選択すると、コントロールの値が変わります。
Slider は、
Domain オブジェクトを使用して一連の値を定義します。
StandardIntDomain などの多くの標準ドメインでは、既定値を指定し、最小値と最大値が存在しない場合は
null を使用します。スライダ コントロールで使用可能な値を無限にすることはできません。そのため、
Slider で
Domain を使用する場合は、最小値と最大値を指定する必要があります。使用可能な値は、最大値と最小値の間にある、指定したデータ型の値です。
次の例は、ドメインとプロパティの既定値を使用した
Slider と、変更値と終了値の表示を有効にするイベント ハンドラを示しています。
Slider で使用する既定のドメインは、
0 から
100 までの整数で、既定値は
0 です。
Slider の動作について、次の点に注意してください。
例:
既定の Slider |
|
{let changed-value:TextField = {TextField}}
{let finished-value:TextField = {TextField}}
{HBox
valign = "top",
{Slider
{on ValueChanged at s:Slider do
set changed-value.value = {String s.value}
},
{on ValueFinished at s:Slider do
set finished-value.value = {String s.value}
}
},
{Table
{row-prototype "Changed value: ", {value changed-value}},
{row-prototype "Finished value: ", {value finished-value}}
}
}
| |
次の例では、スライダで float ドメインを使用しています。
例:
Float ドメイン |
|
{value
let changed-value:TextField = {TextField}
let finished-value:TextField = {TextField}
let slide:Slider =
{Slider
width = 10cm,
domain =
{StandardFloatDomain
default-value = 0,
min-allowable = 0,
max-allowable = 50
},
{on ValueChanged at s:Slider do
set changed-value.value = {String s.value}
},
{on ValueFinished at s:Slider do
set finished-value.value = {String s.value}
}
}
{VBox
slide,
{HBox
"changed value:",
changed-value,
"finished value:",
finished-value
}
}
}
| |
例:
Time ドメイン |
|
{let changed-value:TextField = {TextField}}
{let finished-value:TextField = {TextField}}
{let times:{Array-of Time} =
{new {Array-of Time}}
}
{for i:Time = 0s to 60s step 1s do
{times.append i}
}
{let slide:Slider =
{Slider
width = 12cm,
domain =
{StandardTimeDomain
allowable-values = times
},
major-tick-spacing = 15,
minor-tick-spacing = 5,
{on ValueChanged at s:Slider do
set changed-value.value = {String s.value}
},
{on ValueFinished at s:Slider do
set finished-value.value = {String s.value}
}
}
}
{VBox
slide,
{HBox
"changed value:",
changed-value,
"finished value:",
finished-value
}
}
| |
Slider は、
SpinControl と同じように列挙型を処理します。値は、列挙体で指定された順にコントロールに表示されます。
major-tick-spacing と
minor-tick-spacing の既定値は、列挙値を使用するスライダでは正常に機能しない場合があります。次の例では、これらの両方のプロパティを
1 に設定して、7 つの曜日すべてに主目盛りとラベルを表示しています。主目盛りの間隔を
2 に変更して、曜日のラベルが 1 つおきに表示されることを確認してください。
例:
列挙型のドメイン |
|
{let changed-value:TextField = {TextField}}
{let finished-value:TextField = {TextField}}
{define-enum public Days
Sunday = "Sunday",
Monday= "Monday",
Tuesday = "Tuesday",
Wednesday = "Wednesday",
Thursday = "Thursday",
Friday = "Friday",
Saturday = "Saturday"
}
{let slider:Slider =
{Slider
width = 12cm,
domain =
{Domain.from-type
Days
},
major-tick-spacing = 1,
minor-tick-spacing = 1,
{on ValueChanged at s:Slider do
set changed-value.value = {String s.value.value}
},
{on ValueFinished at s:Slider do
set finished-value.value = {String s.value.value}
}
}
}
{VBox
slider,
{HBox
"Changed value:",
{Fill},
{value changed-value},
"Finished value:",
{Fill},
{value finished-value}
}
}
| |
Slider には、コントロールのラベルと目盛りマークを変更するためのプロパティが用意されています。次の例では、
Slider.snap-to-ticks? を
true に設定して、ユーザーがスライダのつまみを目盛りマークの間に移動できないようにしています。このプロパティ設定は、ユーザーが使用できる値を制限する点で
SpinControl.step の設定と同じ効果を持ちます。この例では、使用可能な値は
0 と
50 の間のすべての整数です。ただし、スライダのつまみを 5 単位でしか移動できないため、値も 5 単位でしか選択できません。
例:
snap-to-ticks? の使用 |
|
{value
let changed-value:TextField = {TextField}
let finished-value:TextField = {TextField}
let slider:Slider =
{Slider
width = 10cm,
snap-to-ticks? = true,
domain =
{StandardIntDomain
default-value = 0,
min-allowable = 0,
max-allowable = 50
},
{on ValueChanged at s:Slider do
set changed-value.value = {String s.value}
},
{on ValueFinished at s:Slider do
set finished-value.value = {String s.value}
}
}
{VBox
slider,
{HBox
"changed value:",
changed-value,
"finished value:",
finished-value
}
}
}
| |
例:
目盛りとラベルのバリエーション |
|
{spaced-hbox
valign = "center",
{Slider show-ticks? = false},
{Slider show-labels? = false},
{Slider
show-ticks? = false,
show-labels? = false
}
}
| |
Slider.labels プロパティでは、目盛りラベルとして機能するグラフィックを指定できます。値と対応するグラフィックのハッシュ テーブルを指定する必要があります。
次の例は、グラフィカルなラベルを有効に活用できる状況を示しています。ラベルは、スライダのつまみを右側に移動するにつれて高くなる色の濃度を表しています。
例:
ラベルとしてのグラフィックの使用 |
|
{let r:double = .5, g:double = .5, b:double = .5}
{let dom:Domain =
{StandardDoubleDomain
default-value = 0.5,
min-allowable = 0.0,
max-allowable = 1.0
}
}
{let f:Fill =
{Fill
width = 5cm,
height = 5cm,
background = {Color.from-rgb r, g, b}
}
}
{define-proc public
{make-labels color:String, how-many:int}:{HashTable-of any, Graphic}
{let r:double = 1, g:double = 1, b:double = 1}
let ht:{HashTable-of any, Graphic} = {new {HashTable-of any, Graphic}}
{for i:double = 0 to how-many step 0.1 do
{if color == "red" then
set b = 1 - i
set g = b
elseif color == "green" then
set r = 1 - i
set b = r
else
set g = 1 - i
set r = g
}
{ht.set i,
{Fill width = 2mm, height = 3mm,
vorigin = "top", background = {Color.from-rgb r, g, b}}}
}
{return ht}
}
{spaced-hbox valign = "center",
f,
{spaced-vbox
{Slider
width = 7cm,
domain = dom,
format-spec = "%.1f",
labels = {make-labels "red", 10},
major-tick-spacing = 0.1,
minor-tick-spacing = 0.05,
{on ValueChanged at s:Slider do
set r = s.value asa double
set f.background = {Color.from-rgb r, g, b}
}
},
{Slider
width = 7cm,
domain = dom,
format-spec = "%.1f",
labels = {make-labels "green", 10},
major-tick-spacing = 0.1,
minor-tick-spacing = 0.05,
{on ValueChanged at s:Slider do
set g = s.value asa double
set f.background = {Color.from-rgb r, g, b}
}
},
{Slider
width = 7cm,
domain = dom,
format-spec = "%.1f",
labels = {make-labels "blue", 10},
major-tick-spacing = 0.1,
minor-tick-spacing = 0.05,
{on ValueChanged at s:Slider do
set b = s.value asa double
set f.background = {Color.from-rgb r, g, b}
}
}
}
}
| |
次の例は、目盛りとラベルを使用しなくてもスライダを効果的に表現できることを示しています。この例は、
control-color を使用してスライダ値の情報を伝達します。目盛りを表示しない場合でも、主目盛りと補助目盛りの間隔を設定する必要があります。または、方向キーと Page キーが正しく動作するように
Slider.blocksize と
Slider.unitsize を設定する必要があります。
例:
ラベルと目盛りのないスライダ |
|
{let r:double = .5, g:double = .5, b:double = .5}
{let dom:Domain =
{StandardDoubleDomain
default-value = 0.5,
min-allowable = 0.0,
max-allowable = 1.0
}
}
{let f:Fill =
{Fill
width = 3cm,
height = 3cm,
background = {Color.from-rgb r, g, b}
}
}
{spaced-hbox valign = "center",
f,
{spaced-vbox
{Slider
width = 7cm,
domain = dom,
control-color =
{LinearGradientFillPattern
{Fraction2d 0, 1},
{Fraction2d 1, 1},
{Spectrum.from-endpoints
"white",
"red"
}
},
show-labels? = false,
show-ticks? = false,
major-tick-spacing = 0.1,
minor-tick-spacing = 0.05,
{on ValueChanged at s:Slider do
set r = s.value asa double
set f.background = {Color.from-rgb r, g, b}
}
},
{Slider
width = 7cm,
domain = dom,
control-color =
{LinearGradientFillPattern
{Fraction2d 0, 1},
{Fraction2d 1, 1},
{Spectrum.from-endpoints
"white",
"green"
}
},
show-labels? = false,
show-ticks? = false,
major-tick-spacing = 0.1,
minor-tick-spacing = 0.05,
{on ValueChanged at s:Slider do
set g = s.value asa double
set f.background = {Color.from-rgb r, g, b}
}
},
{Slider
width = 7cm,
domain = dom,
control-color =
{LinearGradientFillPattern
{Fraction2d 0, 1},
{Fraction2d 1, 1},
{Spectrum.from-endpoints
"white",
"blue"
}
},
show-labels? = false,
show-ticks? = false,
major-tick-spacing = 0.1,
minor-tick-spacing = 0.05,
{on ValueChanged at s:Slider do
set b = s.value asa double
set f.background = {Color.from-rgb r, g, b}
}
}
}
}
| |
エンド ユーザーが範囲を設定できる例を次に示します。このスライダは、別の範囲が選択されるか、
Clear range というラベルのボタンで
Slider.has-range? が
false に設定されるまで、選択された範囲を保持します。
例:
範囲の選択 |
|
{let begin-value:TextField = {TextField}}
{let end-value:TextField = {TextField}}
{let single-value:TextField = {TextField}}
{let slide:Slider =
{Slider
width = 12cm,
allow-range? = true,
{on ValueFinished at s:Slider do
{if s.has-range? then
let begin:any, end:any
set (begin, end) = {s.get-range}
set begin-value.value = {String begin}
set end-value.value = {String end}
set single-value.value = {String s.value}
else
set single-value.value = {String s.value}
}
}
}
}
{VBox
slide,
{HBox
"Start:",
{value begin-value},
"End:",
{value end-value},
"Value:",
{value single-value},
{CommandButton
label = "Clear range",
{on Action do
set slide.has-range? = false
set begin-value.value = ""
set end-value.value = ""
}
}
}
}
| |
次の例は、スライダでのその他の範囲の使用法を示しています。範囲をプログラムで設定し、範囲外の値を識別します。
Slider.allow-range? は既定値の
false であるため、ユーザーは範囲を設定できません。
例:
範囲の限定 |
|
{let begin:any = 20, end:any = 80}
{let slide:Slider =
{Slider
width = 12cm,
{on ValueFinished at s:Slider do
{if s.value asa int < begin asa int
or s.value asa int > end asa int then
{popup-message color = "red", "OUT OF RANGE"}
}
}
}
}
{slide.set-range begin, end}
{value slide}
| |
Scrollbar は、両端にボタンのある幅の細いバーと、セントラル チャネル、
thumb と呼ばれる第三のボタンで構成されています。
thumb は、
Scrollbar.min と
Scrollbar.max の値の間で
Scrollbar の値が変化するにつれてチャネルの両端の間をスライドします。
Scrollbar は Value コントロールではありません。
Scrollbar の値として参照されるのは、チャネル内で thumb の位置を表す任意の数です。
Scrollbar と関連付けられているイベントの1つは、
Adjustment イベントで、
Scrollbar の値が変更されるたびに発生します。
Scrollbar の値はユーザー 操作によっても、またプログラムによっても設定することができます。ユーザーは矢印ボタンをクリックしてユニット スクローリングを使用するか、チャネルをクリックしてブロック スクローリングを使用することができます。
Scrollbar.unitsize はユニット スクローリングで値を変更するのに使用された増分を決定し、
Scrollbar.blocksize はブロック スクローリングで使用された増分を決定します。
次の例では、
get-scroll-value メソッドと
min および
max プロパティーを使用してスライダーがいずれかの終点に達したときにメッセージをポップアップする、簡単な
Scrollbar を示します。また
thickness も使用してスクロール バー のチャネルとボタンの幅を設定します。
Scrollbar.thumb-length は thumb ボタンの長さを決定します。
ScrollBox を使用する際、関連付けられているスクロール バーの thumb の長さは表示画面とコンテンツのサイズの割合を反映して自動的に計算されます。スクロールバーを直接作成する場合は、thumb の長さを設定できます。既定の長さは 0 です。
thumb-length が 0 より大きい場合は、スクロール バーが持つことができる最大値は
Scrollbar.max -
Scrollbar.thumb-length です。次の例では、
thumb-length の値を 0 より大きく設定した場合、コントロールの右端にメッセージ ダイアログをポップアップさせることができないので注意してください。
例:
水平方向の ScrollBar |
|
{Scrollbar
width = 10cm,
direction = Orientation.horizontal,
thickness = 1cm,
||-- thumb-length = 1,
{on adjust:Adjustment at sb:Scrollbar do
{if ({sb.get-scroll-value} == sb.min
or {sb.get-scroll-value} == sb.max) then
{popup-message
modal? = false,
"You can't go any farther that way!"
}
}
}
}
| |
Scrollbar を使用して、一種の仮想のスクロール ボックスを作成することができます。サーバー上にデータがある状況を想定してください。総レコード数を決定し、レコードの範囲を要求することができます。たとえば、最初に 10、その後次の 10 、というように、です。隣にあるスクロール バーでコンテナ内に一度に 10 レコードを表示することができます。ユーザーがスクロール バーを上下にスクロールすると、
Scrollbar の
Adjustment イベント ハンドラが要求されているレコードをロードします。この方法で、一度にすべてのデータをダウンロードすることなく、すべてのデータセットをスクロールすることができます。
次の例では、この方法をシミュレーションしています。データベースのレコードの代わりに、アルファベットの文字を表す海上信号旗の画像をロードします。
Scrollbar.max は使用可能な画像数を示しています。画像を表示する
VBox は2つの画像に十分な大きさです。
blocksize はブロック スクローリングを一度に2つの画像に、
unitsize はユニット スクローリングを1つの画像に設定します。
thumb-length は単位サイズに等しく、したがってthumb はチャネルの長さ全体を行き来します。
Scrollbar.quantized? は
true に設定され、値は単位サイズの倍数になります。
例:
仮想のスクロールボックス作成 |
|
{let flags:{Array-of String} =
{new {Array-of String},
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
}
}
{let flag-box:VBox =
{VBox
height = 41px * 2,
{image source = {url "../../default/images/a-icon.gif"}},
{image source = {url "../../default/images/b-icon.gif"}}
}
}
{let f:Frame =
{Frame flag-box}
}
{let sb:Scrollbar =
{Scrollbar
direction = Orientation.vertical,
min = 0,
max = 25,
thumb-length = 1,
blocksize = 2,
unitsize = 1,
quantized? = true,
{on e:Adjustment at s:Scrollbar do
let ix:int = {s.get-scroll-value} asa int
{if ix < s.max then
{flag-box.clear}
{flag-box.add {image source = {url "../../default/images/" & flags[ix] & "-icon.gif"}}, index = 0}
{flag-box.add {image source = {url "../../default/images/" & flags[ix + 1] & "-icon.gif"}}, index = 1}
}
}
}
}
{HBox
sb,
f
}
| |
GroupBox は、ユーザー インターフェイスの他のコントロールをグループ化してグループのラベルを指定する単純なコントロールです。
GroupBox を使用して、容易に理解できナビゲート可能な、ビジュアル面で優れた UI にすることができます。次の例は、
GroupBox を使用してコントロールを 2 つの領域にグループ化しています。1 つは名前を入力するための
Name: というグループで、もう 1 つは住所を入力するための
Address: というグループです。コントロールを
Tab キーで移動すると、
GroupBox は選択されず、フォーカスを受け取りません。
GroupBox.tab-index プロパティは、ボックスの内容へのタブ トラバーサルの順序を制御します。コントロール間のナビゲーションの詳細と
GroupBox の使用例については、「
Navigation (ナビゲーション)」を参照してください。
例:
GroupBox によるコントロールの構成 |
|
{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"
}
}
{Dialog
{VBox
{GroupBox
label = "Name: ",
{Table
{row-prototype "First Name", {TextField}},
{row-prototype "Last Name", {TextField}}
}
},
{GroupBox
label = "Address: ",
{Table
{row-prototype "Street", {TextField}},
{row-prototype "State",
{DropdownList
data-model = list-of-states,
prompt = "Choose a state:",
dropdown-height = 3cm
}
},
{row-prototype "Zip Code", {TextField}}
}
}
}
}
| |
Copyright © 1998-2019 SCSK Corporation.
All rights reserved.
Curl, the Curl logo, Surge, and the Surge logo are trademarks of SCSK Corporation.
that are registered in the United States. Surge
Lab, the Surge Lab logo, and the Surge Lab Visual Layout Editor (VLE)
logo are trademarks of SCSK Corporation.