定義構築ブロック
GUIKit の定義は,Wolfram言語式の形式で定義されようとXML形式のGUIKitXMLで定義されようと,ウィジェットの階層によって定義される.単一の自己完結的なユーザインターフェース定義は,常にウィンドウかフレームのインスタンスである最も外側のユーザインターフェースウィジェットから始めなければならない.GUIKit のフレームワークは,ルートインターフェース定義ウィジェットが少なくともウィンドウまたはフレーム内に置くことのできるユーザインターフェースクラスである場合に,実際にトップレベルのフレームまたはウィンドウウィジェットの使用を要求されないように,オプショナルに適切なトップレベルのウィンドウラッパを提供する.こうすると,Widget["Panel"]というルートウィジェットでそれらをデザインすることで再利用可能な複合ウィジェットを書くことができるので便利である.これは,それ自身で実行することもできるし他のデベロッパウィンドウ定義内のコンテンツとして再利用することもできる.続くドキュメントセクションにはパネルデザインのハイレベルウィジェットの再利用の例がある.
ユーザインターフェース定義を構成する構築ブロックのいくつかには以下が含まれる.
Widget["path" | "class:className", {*definitions and child widgets*}, Name -> "myName"]myName(Nameオプション使用)ですでに登録されている既存ウィジェットを参照する.
WidgetReference["myName"]Wolfram言語のスクリプトコードブロックは,ユーザインターフェース内で定義されたウィジェットオブジェクトへのアクセスを持つユーザインターフェースインスタンスのコンテキスト内で実行された任意のWolfram言語プログラミングコードを含んでいる.
Script[*expr*]イベントバインディングによって,ユーザインターフェース内で何等かのイベントが起った場合にWolfram言語コードが実行される.
BindEvent["eventName", Script[*expr*]]インターフェース内のライブウィジェットの状態を設定する,あるいは得る.
SetPropertyValue[{"widgetName", "propertyName"}, val] or {"widgetName", "propertyName"} -> val
PropertyValue[{"widgetName", "propertyName"}]
PropertyValue[{"widgetName", "propertyName", index}]ウィジェット定義が作成時に引数を必要とするときは,InitialArgumentsで設定することができる.
前述のWolfram言語構築ブロック式に類似したユーザインターフェース定義を定義するXML要素の同等のセットがある.
ウィジェットのレイアウト
GUIKit 定義は,ウィジェットの階層的な「木」の式として定義される.しかし,同時に定義のネスト構造とリストの深さもまたウィジェットが視覚的にどのようにランタイムにレイアウトされるかを決める要素になる.レイアウト規則の目的は定義中で簡単に表すことができる最も一般的で役に立つ形式を作り上げ,かつ必要な選択的規則を提供してレイアウトのよりきめ細かい制御を可能にすることにある.また,レイアウトの規則は馴染み深いWolfram言語リストの構造になっており,基礎になっているJava描画実装レイアウトAIPに関する知識は必要ない.この決定的なレイアウトのハイレベルの抽象化によって,単純で即時的かつ直感的なレイアウトが,すべての最新ユーザインターフェースダイアログがサイズ調整時に踏襲すると考えられる欠くことのできない動的レイアウトのサイズ調整機能とともに提供される.
Needs["GUIKit`"];単にウィジェット式を別のウィジェット式の中にネストさせ,結果の自動的な垂直および水平グループ化を決定する{…}ネストの希望レベルを選ぶだけで希望するインターフェース定義のレイアウトの外見のほとんどを作り出すことができる.
GUIKit ウィジェットレイアウトシステムでは次の基本的なヒューリスティックが使われている.
- 最も外側(トップレベル)のウィジェットリスト,Widget[comp,children_List]の子ウィジェット,はデフォルトで垂直(列)レイアウトを使う
デフォルトで,子ウィジェットのリストはパネルの左辺から始まる列の中で垂直にレイアウトされる.
ref = GUIRun[
Widget["Panel", {
Widget["Button", {"text" -> "Button A"}],
Widget["Button", {"text" -> "Button B"}],
Widget["Button", {"text" -> "Button C"}] }
]
];GUIScreenShot[ref]垂直のレイアウト内にリストをネストさせると内部グループが水平にレイアウトされる.
ref = GUIRun[
Widget["Panel", {
{Widget["Button", {"text" -> "Button A"}],
Widget["Button", {"text" -> "Button B"}]},
Widget["Button", {"text" -> "Button C"}] }
]
];GUIScreenShot[ref]さらにネストさせると垂直のネストと水平のネストが交互に繰り返される.
ref = GUIRun[
Widget["Panel", {
{Widget["Button", {"text" -> "Button A"}],
{Widget["Button", {"text" -> "Button B-1"}],
Widget["Button", {"text" -> "Button B-2"}]}},
Widget["Button", {"text" -> "Button C"}] }
]
];GUIScreenShot[ref]次は,ウィジェットのタイプによってデフォルトでその最大サイズとなるものとならないものがあることが分かる.これはユーザの期待に沿っている.
ref = GUIRun[
Widget["Frame", {
{Widget["Label", {"text" -> "Label:"}],
Widget["TextField", {"text" -> "Input"}]},
Widget["TextArea", {"text" -> "Content"}] }, Name -> "myFrame"]
];GUIScreenShot[ref]ウィンドウサイズを変更すると,デフォルトでテキストフィールドのサイズが水平方向に調整されるのに対し,テキストフィールドの大きさは両方向に拡大されることに注意.
ref @ Script[
SetPropertyValue[{"myFrame", "size"},
Widget["Dimension", {"width" -> 250, "height" -> 150}]];
InvokeMethod[{"myFrame", "validate"}];
]GUIScreenShot[ref]ウィジェットの単純なネストでは希望するレイアウトあるいは特徴のサイズ変更の達成に十分ではない場合でも,結果の微調整に役立つ数多くの追加的なWidgetインターフェース定義式やオプションがある.追加的な定義式にはWidgetGroup,WidgetFill,WidgetSpace,WidgetAlignおよび "Stretching","Alignment","Grouping","Spacing","Border"要素等の機能のデフォルト値を交互に選ぶことができるWidgetとWidgetGroupのオプションがある.
WidgetGroup
リストのネストの深さに基づいているデフォルトのレイアウト揃えが適切ではない場合,WidgetGroup[{…},WidgetLayout->Row]あるいはWidgetGroup[{…},WidgetLayout->Column]の形式を使って明示的に次の揃えを指定することができる.
| WidgetGroup[{…},WidgetLayout->Row] | |
| 明示的に子ウィジェットの水平レイアウトを強制する | |
| WidgetGroup[{…},WidgetLayout ->Column] | |
| 明示的に子ウィジェットの垂直レイアウトを強制する | |
WidgetGroupの使用法の基本形
| WidgetGroup[{group1,group2,…}, WidgetLayout->{"Grouping"->{Tabs,{"Tab Label1","Tab Label2",…}}}] | |
| ラベル付きのタブを生成されたタブ付きウィンドウ枠の最上部に置く | |
| WidgetGroup[{group1,group2,…}, WidgetLayout->{"Grouping"->{Tabs,Bottom,"Tab Label1","Tab Label2",…}}}] | |
| ラベル付きのタブを最下部に置く | |
| WidgetGroup[{group1,group2},WidgetLayout->Split,Name->"mySplitPane"] | |
| サイズ調整が可能な分割バーを2つのグループの間に置き,生成された分割ウィンドウ枠に任意で"mySplitPane"と名付ける | |
| WidgetGroup[{group1,group2},WidgetLayout->{"Grouping"->{Split,Vertical}}] | |
| 垂直の分割バーを使う | |
| WidgetGroup[{group1,group2},WidgetLayout->{"Grouping"->{Split,Horizontal}}] | |
| 水平の分割バーを使う | |
| WidgetGroup[{{…},{…},…},WidgetLayout->Grid] | |
| 等分に整列された要素の格子を代替物として使って,ネストした行と列のリストを操作する(しかし、この形式には子ウィジェットリストのサイズ調整と交代にある種の制限がある) | |
明示的にトップレベルに行のレイアウトを選ぶことで通常は垂直のレイアウトであるものを無効にすることができる.
ref = GUIRun[
Widget["Panel", WidgetGroup[{
Widget["Button", {"text" -> "Button A"}],
Widget["Button", {"text" -> "Button B"}],
Widget["Button", {"text" -> "Button C"}] }, WidgetLayout -> Row]
]
];GUIScreenShot[ref]ネストしたリストも自動的に水平レイアウトと垂直レイアウトを交互に選ぶので,子リストはここでは列になる.
ref = GUIRun[
Widget["Panel", WidgetGroup[{
{Widget["Button", {"text" -> "Button A"}],
Widget["Button", {"text" -> "Button B"}]},
Widget["Button", {"text" -> "Button C"}] }, WidgetLayout -> Row]
]
];GUIScreenShot[ref]ウィジェットリストの一部または全部をWidgetGroup式で明示的に置換することができる.
ref = GUIRun[
Widget["Panel", WidgetGroup[{
{Widget["Button", {"text" -> "Button A"}],
WidgetGroup[{
Widget[" Button", {"text" -> "Button B-1"}],
Widget["Button", {"text" -> "Button B-2"}]}, WidgetLayout -> Column]},
Widget["Button", {"text" -> "Button C"}] }, WidgetLayout -> Row]
]
];GUIScreenShot[ref]ref = GUIRun[
Widget["Panel",
WidgetGroup[{
{Widget["Label", {"text" -> "A:"}],
Widget["TextField", {"text" -> "A content"}]},
{Widget["Label", {"text" -> "B:"}],
Widget["TextField", {"text" -> "B content is the largest of all"}]},
{Widget["Label", {"text" -> "C:"}],
Widget["TextField", {"text" -> "C content is larger than A"}]}
}, WidgetLayout -> Grid]
]
];GUIScreenShot[ref]次は,タブ付きのウィンドウ枠のセット内にコンテンツを生成する例題である.
ref = GUIRun[
Widget["Panel",
WidgetGroup[{
{Widget["Button", {"text" -> "Button A"}], Widget["TextField", {"text" -> "someA"}]}, {Widget["Button", {"text" -> "Button B"}], Widget["TextField", {"text" -> "someB"}]}
}, Name -> "myTabPane",
WidgetLayout -> {"Grouping" -> {Tabs, Bottom, {"One", "Two"}}}]
]
]GUIScreenShot[ref]タブ付きのWidgetGroupの各要素は1つのタブパネルまたはコンテンツが1つのウィンドウ枠に置かれる1つのウィジェットが入ったウィジェットのリストでもよい.
ref = GUIRun[
Widget["Panel",
WidgetGroup[{
Widget["Wolfram/Example/PrimeFinder"],
Widget["Wolfram/Example/CellularGroup"]
}, Name -> "myTabPane",
WidgetLayout -> {"Grouping" -> {Tabs, Top, {"One", "Two"}}}]
]
]GUIScreenShot[ref]次は,分割されたウィンドウ枠に,ランタイムでその特性を使って操作できるように任意でどのように命名するかを示したものである.
ref = GUIRun[
Widget["Panel",
WidgetGroup[{
Widget["Button", {"text" -> "Button B"}],
WidgetGroup[{Widget["Button", {"text" -> "Button A"}], Widget["TextField", {"text" -> "some"}]}, WidgetLayout -> Column]
}, WidgetLayout -> {"Grouping" -> {Split, Vertical}}, Name -> "mySplitPane"]
]
]GUIScreenShot[ref]ref @ PropertyValue[{"mySplitPane", "dividerLocation"}]パネルを少し大きくすると,分割位置をプログラム的に移動することが可能なことが分かる.
ref @ SetPropertyValue[{"mySplitPane", "dividerLocation"}, 50]GUIScreenShot[ref]また,整数の特性値の代りに百分率の値を使ってメソッドを呼び出すこともできる.
ref @ InvokeMethod[{"mySplitPane", "setDividerLocation"}, 0.50]WidgetFill
WidgetFill[]要素は自身が置かれたレイアウトの方向に沿ってできる限り自身を強制拡張し,自身のグループ内の他のウィジェットを片側に「押しやる」「スプリングの拡張」として利用することができる.
多分,WidgetFill[]の最も一般的な使用法は,サイズ変更時にひとまとまりの水平ボタンを右寄せにすることだろう.
ref = GUIRun[
Widget["Panel", {
Widget["TextArea", {"text" -> "Some content", "rows" -> 4, "columns" -> 30}],
{
WidgetFill[],
Widget["Button", {"text" -> "OK"}],
Widget["Button", {"text" -> "Cancel"}]
}
}]
];GUIScreenShot[ref]WidgetSpace
WidgetSpace[n]要素はウィジェットが置かれたレイアウトの方向に沿ってウィジェット間の明示的な間隔要素として使うことができる.
ref = GUIRun[
Widget["Panel", {
Widget["TextArea", {"text" -> "Some content", "rows" -> 4, "columns" -> 30}],
{
WidgetFill[],
Widget["Button", {"text" -> "OK"}],
WidgetSpace[10],
Widget["Button", {"text" -> "Cancel"}]
}
}]
];GUIScreenShot[ref]WidgetAlign
WidgetAlign[]要素はウィジェットリストのグループ内におけるプレースホルダ要素として作用し,兄弟リスト内に存在する各リストに対しては,対応する整列マーカー間に同数のウィジェットが存在することは強制せずに,ある種の格子構造を強制し,自分自身をWidgetAlign[]の他のインスタンスと整列させるように試みる.これらはワープロ文書におけるマーカーと同様の機能を持つ.
これとは別の,少々高度なWidgetAlignの形式にWidgetAlign[{"widgetName",After|Before},Before|After]がある.これはWidgetAlignのすぐ次のウィジェットの先頭または末尾(BeforeあるいはAfter)が"widgetName"という名前の他のウィジェットの先頭または末尾と揃うように指定する.この形式はその使用が少々限定され,正しく作用するために適切な位置における適切に命名されたウィジェットの依存性を必要とする.
次では,兄弟ウィジェットリストを揃えたいところにWidgetAlign[]マーカー要素を置く.
Needs["GUIKit`"];ref = GUIRun[
Widget["Panel", {
{Widget["TextField", {"text" -> "A1"}],
WidgetAlign[],
Widget["TextField", {"text" -> "A2"}],
Widget["TextField", {"text" -> "A3"}],
WidgetAlign[],
Widget["TextField", {"text" -> "A4"}]
},
{Widget["TextField", {"text" -> "B1"}],
Widget["TextField", {"text" -> "B2"}],
WidgetAlign[],
Widget["TextField", {"text" -> "B3"}],
WidgetAlign[],
Widget["TextField", {"text" -> "B4"}],
Widget["TextField", {"text" -> "B5"}]
}
}]
];GUIScreenShot[ref]WidgetLayoutのオプション
先に説明したように,WidgetLayoutは含んでいるウィジェットのグループ化の方向を指定することができるWidgetGroupのオプションである.実際のところ,WidgetLayout->groupValue の形式はWidgetLayout->{"Grouping"->groupValue}の略式表記である. 結局のところ,レイアウトに異なる微調整を施すWidgetLayoutのサブプションはたくさんある.WidgetLayoutのみを使ってグループ化の選択を指定するのが非常に一般的なのでグループ化の短縮形は使用可能である.
WidgetLayoutを使った短縮形の別のものにWidgetとともに使うものがある.これはユーザインターフェースを構築したいが親ウィジェットのレイアウトに自動的にウィジェットを追加したくないという特別の場合のためのものである.この場合は,WidgetLayout->Noneを使ってこのウィジェットレイアウトの動作をオフにする.
| WidgetLayout->groupValue | WidgetLayout->{"Grouping"->groupValue}の短縮形 |
| WidgetLayout->None | Widgetのオプションで,親ウィジェットとの任意の自動インターフェースレイアウトをオフにする |
WidgetLayoutの短縮形についてこれまでに説明したすべての形式を許容する"Grouping"に加え,Row,Column,Grid,Automatic,Noneが既存の他のWidgetLayoutサブオプションに続く.
"Grouping"
"Grouping"->groupValue は,これまでに説明したWidgetLayoutの短縮形についてドキュメントされたすべてのグルーピング値を取る.このサブオプション形は任意のWidgetGroupに対して他のWidgetLayoutサブオプションが組み合されたときには必ず使わなければならない.
前セクションのWidgetLayout->groupValue の例題中の"Grouping"を使った例を参照のこと.
"Stretching"
"Stretching"サブオプションはWidgetとWidgetGroupの両方でサポートされており,任意のウィジェットタイプでデフォルトの伸張特性とは異なる水平および垂直の伸張を指定するときに便利である.水平の伸張値も垂直の伸張値も, None,False,WidgetAlign,TrueおよびMaximizeの値で指定することができる.
| "Stretching"->{horizontal,vertical} | 指定のウィジェットのデフォルトの伸張特性を無効にする. |
| "Stretching"->None | ウィジェットが最初の大きさから伸長されないようにする. |
| "Stretching"->False | "Stretching"->Noneに等しい. |
| "Stretching"->True | 伸張は許すが,Maximizeの伸張を持つ他のウィジェットが存在する場合はこれにより制限が生じることがある |
| "Stretching"->Maximize | 伸張を許し,他の伸張のみを許すウィジェットに対するこの特性を持つウィジェットの伸張を優先させる |
| "Stretching"->WidgetAlign | 伸張は許すが,その伸張はリスト中の兄弟ウィジェットと同じ大きさまでに制限する |
デフォルトではラベルは伸張されないがテキストフィールドは伸長される.明示的な"Stretching"値でこれを無効にすることができる.
ref = GUIRun[
Widget["Frame", {
{Widget["Label", {"text" -> "Label:"}, WidgetLayout -> {"Stretching" -> {True, False}}],
Widget["TextField", {"text" -> "Input"}, WidgetLayout -> {"Stretching" -> {False, False}}]},
Widget["TextArea", {"text" -> "Content"}] }, Name -> "myFrame"]
]GUIScreenShot[ref]ref @ SetPropertyValue[{"myFrame", "size"},
ref @ Widget["Dimension", {"width" -> 250, "height" -> 150}]]GUIScreenShot[ref]"Alignment"
"Alignment"サブオプションはWidgetとWidgetGroupの両方でサポートされており,水平と垂直の両方の整列に使用できる.垂直軸に沿ったデフォルトの整列値はLeftで,取り得る値はLeft,Center,Rightである.水平軸に沿ったデフォルトの整列値はCenterで,取り得る値はTop,Center,Bottomである.どちらの軸もAutomaticとすると適切なデフォルト値が選ばれる.
入力に対応するテキストフィールドのラベルは右揃えにするのが一般的である.
ref = GUIRun[
Widget["Panel",
WidgetGroup[{
{Widget["Label", {"text" -> "One:"}, WidgetLayout -> {"Alignment" -> {Right, Automatic}}],
Widget["TextField", {"text" -> "A content"}]},
{Widget["Label", {"text" -> "OneLonger:"}, WidgetLayout -> {"Alignment" -> {Right, Automatic}}],
Widget["TextField", {"text" -> "B content is the largest of all"}]}
}, WidgetLayout -> Grid]
]
];GUIScreenShot[ref]"Border"
"Border"サブオプションはウィジェットグループの周りの一般的な境界スタイルを構築するのに便利な方法である.スペースのみを指定する境界,名前と罫線による枠を持つタイトル付きの境界,太さとオプショナルな色の値を持つ単純な線による境界という3つの一般的なタイプがある.
| "Border"->"title" | 罫線のアウトラインが入るタイトル付きの境界スタイルを作る |
| "Border"->{{left,right},{top,bottom}} | |
| 4つの辺のそれぞれに異なるスペースを使う境界を作る | |
| "Border"->n | すべての方向に等しい余白を取るスペースによる境界を作る |
| "Border"->{color,n} | 太さが n で色が color の枠付きの線による境界を作る |
| "Border"->{color,{{left,right},{top,bottom}}} | |
| 辺の太さが異なり色が color の枠付きの線による境界を作る | |
| "Border"->{border1,border2,…} | それぞれの境界スタイルをネストさせた複合境界スタイルを作る |
ref = GUIRun[
Widget["Panel",
WidgetGroup[{
{Widget["Label", {"text" -> "Label:"}],
Widget["TextField", {"text" -> "Input"}]}
}, WidgetLayout -> {"Border" -> "TitleName"}] ]
];GUIScreenShot[ref]あるウィジェット,特にWidget["Panel"]は,「境界」特性を直接設定できるので,ウィジェットレイアウトの"Border"オプションを他のウィジェットとともに直接指定することができる.
ref = GUIRun[
Widget["Panel", {
{Widget["Label", {"text" -> "Label:"}],
Widget["TextField", {"text" -> "Input"}]}
}, WidgetLayout -> {"Border" -> "TitleName"}]
];GUIScreenShot[ref]タイトルとスペース付けの境界の複合境界を使って内側に若干のスペースを加えることができる.
ref = GUIRun[
Widget["Panel",
WidgetGroup[{
{Widget["Label", {"text" -> "Label:"}],
Widget["TextField", {"text" -> "Input"}]}
}, WidgetLayout -> {"Border" -> {"TitleName", {{5, 5}, {10, 30}} } }
] ]
];GUIScreenShot[ref]ref = GUIRun[
Widget["Panel",
WidgetGroup[{
{Widget["Label", {"text" -> "Label:"}],
Widget["TextField", {"text" -> "Input"}]}
}, WidgetLayout -> {"Border" -> {RGBColor[1, 0, 0], 3}}] ]
];GUIScreenShot[ref]"Spacing"
"Spacing"->n サブオプションを使うとWidgetGroupでグループ内のすべてのウィジェット間のスペース要素を全体的に指定することができる.
以下ではグループ内のすべてのウィジェット間のスペースを30ポイントに強制している.
ref = GUIRun[
Widget["Panel",
WidgetGroup[{
{Widget["Label", {"text" -> "A:"}],
Widget["TextField", {"text" -> "A content"}]},
{Widget["Label", {"text" -> "B:"}],
Widget["TextField", {"text" -> "B content is the largest of all"}]},
{Widget["Label", {"text" -> "C:"}],
Widget["TextField", {"text" -> "C content is larger than A"}]}
}, WidgetLayout -> {"Grouping" -> Grid, "Spacing" -> 30}]
]
];GUIScreenShot[ref]