snit2.2/1.3のマニュアルを勝手に日本語に翻訳したものです。ほとんど直訳
オリジナルの文書はhttp://tcllib.sourceforge.net/doc/snit.htmlです。
名前 †
snit -
Snit's Not Incr Tcl
コマンド概略 †
package require Tcl 8.5
package require snit ? 2.2.1 ?
snit::type name definition
typevariable name ? -array ? ? value ?
typemethod name arglist body
typeconstructor body
variable name ? -array ? ? value ?
method name arglist body
option namespec ? defaultValue ?
option namespec ? options... ?
constructor arglist body
destructor body
proc name args body
delegate method name to comp ? as target ?
delegate method name ? to comp ? using pattern
delegate method * ? to comp ? ? using pattern ? ? except exceptions ?
delegate option namespec to comp
delegate option namespec to comp as target
delegate option * to comp
delegate option * to comp except exceptions
component comp ? -public method ? ? -inherit flag ?
delegate typemethod name to comp ? as target ?
delegate typemethod name ? to comp ? using pattern
delegate typemethod * ? to comp ? ? using pattern ? ? except exceptions ?
typecomponent comp ? -public typemethod ? ? -inherit flag ?
pragma ? options... ?
expose comp
expose comp as method
onconfigure name arglist body
oncget name body
snit::widget name definition
widgetclass name
hulltype type
snit::widgetadaptor name definition
snit::typemethod type name arglist body
snit::method type name arglist body
snit::macro name arglist body
snit::compile which type body
$type typemethod args...
$type create name ? option value ... ?
$type info typevars ? pattern ?
$type info typemethods ? pattern ?
$type info args method
$type info body method
$type info default method aname varname
$type info instances ? pattern ?
$type destroy
$object method args...
$object configure ? option ? ? value ? ...
$object configurelist optionlist
$object cget option
$object destroy
$object info type
$object info vars ? pattern ?
$object info typevars ? pattern ?
$object info typemethods ? pattern ?
$object info options ? pattern ?
$object info methods ? pattern ?
$object info args method
$object info body method
$object info default method aname varname
mymethod name ? args... ?
mytypemethod name ? args... ?
myproc name ? args... ?
myvar name
mytypevar name
from argvName option ? defvalue ?
install compName using objType objName args...
installhull using widgetType args...
installhull name
variable name
typevariable name
varname name
typevarname name
codename name
snit::boolean validate ? value ?
snit::boolean name
snit::double validate ? value ?
snit::double name ? option value... ?
snit::enum validate ? value ?
snit::enum name ? option value... ?
snit::fpixels validate ? value ?
snit::fpixels name ? option value... ?
snit::integer validate ? value ?
snit::integer name ? option value... ?
snit::listtype validate ? value ?
snit::listtype name ? option value... ?
snit::pixels validate ? value ?
snit::pixels name ? option value... ?
snit::stringtype validate ? value ?
snit::stringtype name ? option value... ?
snit::window validate ? value ?
snit::window name
説明 †
SnitとはピュアTclのオブジェクト、メガウィジェットシステムです。Tclオブジェクトシステムとしてはユニークな、継承でなく委譲ベースのオブジェクトシステムです。
一般的に、継承ベースのオブジェクトシステムでは、限定された同じシステムでの使用を前提に、定義されたクラスから継承ができるだけです。
Tclにとってオブジェクトとは、オブジェクトのように振舞う何かです。どのようにオブジェクトが実装されているかは問題とするべきではありません。Snitはこれらの材料を使って手軽にアプリケーションを構築することを目的としています。
従って、自前のオブジェクトであろうが、Tkウィジェットであろうが、IncrTclのオブジェクトであろうが、BWidgetであろうが、大体どんなオブジェクトでも組み込んだり構築できるようにSnitは設計されています。
このマニュアルはリファレンス用です。もっとチュートリアルやSnitの概念を知りたい時はsnitfaqを見てください。
Snitのバージョン †
このマニュアルはSnit2.2とSnit1.3を対象にしています。この二つのバージョンの違いは単純です。Snit2.2はTcl8.5の新しい機能を使ったスピードの最適化を含んでいます。Snit1.3はTcl8.3、Tcl8.4、Tcl8.5の全てをサポートしています。
しかしながら、この二つにはいくつかのマイナーな違いがあります。これらの違いは、マニュアルにおいて"Snit 1.x 非互換"というラベルで区別しています。またsnitfaqでも述べています。
リファレンス †
型とウィジェットの定義 †
Snitは新しい型を定義するための次のコマンドを提供します。
- snit::type name definition
nameという名前の新しい抽象データ型を定義します。
もしnameが完全修飾コマンド名(名前空間を含んだ名前)でなければ、snit::typeコマンドが呼び出された名前空間(大抵はグローバル名前空間)にあると仮定されます。このコマンドは新しい型の完全修飾された名前を返します。
その型の名前は、従って、その新しい型のオブジェクトを作成したりなどをするのに使われるコマンドです。
snit::typeのdefinitionブロックは次の定義を含むスクリプトです。
- typevariable name ?-array ? ? value ?
設定された名前nameで型変数を定義。オプションでvalueがあれば、その値を割り当てます。
型変数はこの型の全てのインスタンスで共有されます。もし -arrayオプションがあれば、valueは辞書でなければなりません。array setを使って変数に割り当てられます。
- typemethod name arglist body
新しい型コマンドのサブコマンドである型メソッドを指定された名前、引数リスト、ボディで定義。arglistは普通のTclの引数リストです。デフォルト引数と、args引数を含めることができますが、引数の名前として、type、self、selfns、winを使うことはできません。
type変数は、body中で型の完全修飾名を値を持つ変数として自動的に定義されます。加えて、type変数は、自動的に全ての型メソッドのbody中で可視化されます。
もしnameが二つ以上のトークンを含んでいる時は、Snitはそれを特別に処理します。
typemethod {a b} {arg} { puts "Got $arg" }
この文は暗黙的にbというサブコマンドを持っている、aという名前の型メソッドを定義します。 bはこのように呼び出されます。
$type a b "Hello, world!"
aは色々なサブコマンドを持っているかもしれません。これは階層的なコマンド構造を定義するのを可能にします。これらの多くの例は後述するmethodを見てください。
型メソッドは、型が定義された名前空間からコマンドをインポートすること無しに呼び出すことができます。たとえば、もし、型の名前が ::parentns::typenameなら、型の型メソッドは、 ::parentns::someprocを単にsomeprocとして呼び出すことができます。Snit 1.x 非互換:これはSnit1.xでは動きません。なぜなら、これはTcl8.5の新しいコマンドであるnamespace pathに依存しているからです。
Snit 1.x 非互換:Snit 1.xでは次の二つの型メソッドの呼び出しは同じです。
$type a b "Hello, world!"
$type {a b} "Hello, world!"
Snit2.2では二つ目の呼び出しは不正です。
- typeconstructor body
型コンストラクタのbodyはその型が最初に定義された時に一度だけ実行されます。一般的にはarray変数型の型変数の初期化をしたり、Tkオプションデータベースのエントリを追加したりといったことに使われます。
type変数は、body中で型の完全修飾名を値を持つ変数として自動的に定義されます。加えて、type変数は、自動的に全ての型メソッドのbody中で可視化されます。
型は型コンストラクタを一つだけ定義できます。
型コンストラクタは、型が定義された名前空間からコマンドをインポートすること無しに呼び出すことができます。たとえば、もし、型の名前が ::parentns::typenameなら、型コンストラクタは、 ::parentns::someprocを単にsomeprocとして呼び出すことができます。Snit 1.x 非互換:これはSnit1.xでは動きません。なぜなら、これはTcl8.5の新しいコマンドであるnamespace pathに依存しているからです。
- variable name ? -array ? ? value ?
インスタンス変数を定義します。この型の各インスタンスのプライベート変数です。オプションで初期値を持ちます。もし -arrayオプションがあれば、valueは辞書でなければなりません。array setを使って変数に割り当てられます。
- method name arglist body
インスタンスメソッドを定義。指定された名前、引数リスト、ボディを持つ、この型の各インスタンスのサブコマンドです。arglistは普通のTclの引数リストです。デフォルト引数と、args引数を含めることができます。メソッドは暗黙的に次の引数を追加で渡します。type:型の完全修飾名、self:現在のインスタンスのコマンド名、selfns:寸スタンスのプライベート名前空間、win:オリジナルのインスタンス名。そういうわけで、arglistは引数名として、type, self, selfns, winを含んではいけません。
このように定義されたインスタンスメソッドはローカル定義されたメソッドといいます。
型とインスタンス変数は自動的に全てのインスタンスメソッド中で可視化されます。もしその型がローカル定義されたオプション(後述)を持っていたら、そのoptions配列も可視です。
もしnameが二つ以上のトークンを含んでいる時は、Snitはそれを特別に処理します。
method {a b} {} { ... }
この文は暗黙的にbというサブコマンドを持っている、aという名前の型メソッドを定義します。 bはこのように呼び出されます。
$self a b "Hello, world!"
aは色々なサブコマンドを持っているかもしれません。これは階層的なコマンド構造を定義するのを可能にします。
% snit::type dog {
method {tail wag} {} {return "Wag, wag"}
method {tail droop} {} {return "Droop, droop"}
}
::dog
% dog spot
::spot
% spot tail wag
Wag, wag
% spot tail droop
Droop, droop
%
私たちがしたことは、"wag"と"droop"サブコマンドを持っている"tail"メソッドの暗黙的な定義です。ですから、"tail"を明示的に定義すればエラーになります。
メソッドは、型が定義された名前空間からコマンドをインポートすること無しに呼び出すことができます。たとえば、もし、型の名前が ::parentns::typenameなら、型の型メソッドは、 ::parentns::someprocを単にsomeprocとして呼び出すことができます。Snit 1.x 非互換:これはSnit1.xでは動きません。なぜなら、これはTcl8.5の新しいコマンドであるnamespace pathに依存しているからです。
Snit 1.x 非互換:Snit 1.xでは次の二つの型メソッドの呼び出しは同じです。
$self a b "Hello, world!"
$self {a b} "Hello, world!"
Snit2.2では二つ目の呼び出しは不正です。
- option namespec ? defaultValue ?
- option namespec ? options... ?
この型の各インスタンスのオプションを定義する。初期値が与あればそれを代入する。この初期値に用いられるデフォルトの値は空文字列ですが、defaultValueで変更することができます。
このように定義されたオプションはローカル定義されたものと呼ばれます。
namespecはオプションの名前、リソース名、クラス名を定義したリストです。例:
option {-font font Font} {Courier 12}
オプション名はハイフン(-)で始まらなければなりません。そして、大文字を含んではいけません。リソース名とクラス名は記述しないで省略することができます。リソース名はデフォルトではオプション名の先頭からハイフンを除いたもので、クラス名はデフォルトではリソース名の最初の一文字を大文字にしたものになります。したがって、次の文は、先ほどの例と同じになります。
option -font {Courier 12}
リソースとクラス名についての詳細はTkオプションデータベースを見てください。
オプションは普通セットしたり取り出したりするのに、一般的なインスタンスメソッドのconfigureとcgetを使います。インスタンスのコードの中(メソッドのボディなど)からは、オプションの値はoptions配列から使うことができます。
set myfont $options(-font)
もし型がオプションハンドラ(例:-configuremethod)を定義していたら、ややこしいバグを避けるために、そのオプションにアクセスするときはconfigureとcgetを使うべきでしょう。optionの文は次のオプションを含むことができます。
- -default defvalue
オプションのデフォルト値を定義します。省略された場合、オプションのデフォルト値は空文字列""になります。
- -readonly flag
flagはTclが認識できる真偽値です(true/false, yes/no, 1, 0)。オプションがread-onlyのときは、configureかconfigurelistを使って生成時のみに値を代入することができます。例:型のコンストラクタ。
- destructor body
デストラクタは型のインスタンスが破棄されるときに実行しなければならないコードを定義します。一般的には、コンストラクタで生成した物の破棄に使われます。
デストラクタは明示的に引数を取りません。
メソッドと同様に、type、self、selfns、winの引数が暗黙的に定義されます。そして、全ての型変数とインスタンス変数は自動的にデストラクタのbodyで可視化されます。
メソッドと同様に、デストラクタは、型が定義された名前空間からコマンドをインポートすること無しに呼び出すことができます。たとえば、もし、型の名前が ::parentns::typenameなら、 ::parentns::someprocを単にsomeprocとして呼び出すことができます。Snit 1.x 非互換:これはSnit1.xでは動きません。なぜなら、これはTcl8.5の新しいコマンドであるnamespace pathに依存しているからです。
- proc name args body
型の名前空間に新しくTclプロシージャを定義します。
定義されたプロシージャは、普通のTclプロシージャと全ての型変数は自動的に可視になる点で異なります。さらに、このプロシージャは引数の一つであるselfnsを通じてインスタンス変数にもアクセスできます。
暗黙的に定義されていないとしても、type、self、winという引数の名前は避けるべきです。
メソッドと型メソッドと同様に、プロシージャは、型が定義された名前空間からコマンドをインポートすること無しに呼び出すことができます。たとえば、もし、型の名前が ::parentns::typenameなら、 ::parentns::someprocを単にsomeprocとして呼び出すことができます。Snit 1.x 非互換:これはSnit1.xでは動きません。なぜなら、これはTcl8.5の新しいコマンドであるnamespace pathに依存しているからです。
- delegate method name to comp ? as target
nameという名前のメソッドをcompという名前のコンポーネントに委譲します。つまり、nameメソッドがこの型のインスタンスで呼び出されると、そのメソッドとその引数は、呼び出されたそのメソッドの代わりに、指定されたコンポーネントのコマンドに送られます。つまり、次の文は、
delegate method wag to tail
大雑把に言えば、この明示的に定義されたメソッドと同じです。
method wag {args} {
uplevel $tail wag $args
}
メソッドと同様に、nameは複数のトークンを持つことができます。この場合、その名前の最後のトークンはコンポーネントの名前になります。
オプションのas節は、委譲されたメソッドの名前を設定し、場合によっては追加の引数を付加することを可能にします。
delegate method wagtail to tail as "wag briskly"
メソッドはローカル定義と委譲の両立はできません。
重要:全てのdelegate methodの形式では、インスタンスコンポーネントと型コンポーネントの両方に委譲できます。
- delegate typemethod name to comp ? as target ?
nameの型メソッドを型コンポーネントcompに委譲する。つまり、型メソッドnameが呼び出されると、その型メソッドと引数は指定された型コンポーネントのコマンドに引き渡されます。つまり、次のような文では
delegate typemethod lostdogs to pound
大雑把に言えば、明示的に定義された次のようなメソッドと大体同じです。
typemethod lostdogs {args} {
uplevel $pound lostdogs $args
}
メソッドと同様に、nameは複数のトークンを持つことができます。この場合、nameの最後のトークンはそのコンポーネントのメソッドとして仮定されます。
オプションのas節は、委譲されたメソッドの名前を設定し、場合によっては追加の引数を付加することを可能にします。
delegate typemethod lostdogs to pound as "get lostdogs"
型メソッドはローカル定義と委譲の両立はできません。
- pragma ? options... ?
pragma文はSnitが型を生成する方法をコントロールします。次のオプションを取ります。どのオプションでもflagはTclが認識できる真偽値(0, 1, yes, no, true, false)でなければなりません。
- hastypeinfoと-hastypedestroyと-hasinstancesをFALSEに設定し、適切な型メソッドを定義することで、 副作用無しにアンサンブルコマンドを作成することが出来ます。
- -canreplace flag
FALSE(デフォルト)なら、Snitは既存のコマンドと同じ名前を持つsnit::typeのインスタンスを作成しません。これはややこしいエラーを防ぎます。このプラグマをTRUEに設定すれば、Snit V0.93以前のバージョンの動作と同じになります。
- -hastypeinfo flag
TRUE(デフォルト)なら、生成された型は、型の内省に使われるinfoという型メソッドを持ちます。型メソッドinfoについては後述しています。もしFALSEなら持ちません。
- -hastypedestroy flag
TRUE(デフォルト)なら、生成された型は、その型と、その型の全てのインスタンスを破棄するのに使われるdestroyという型メソッドを持ちます。型メソッドdestroyについては後述しています。もしFALSEなら持ちません。
- -hastypemethods flag
TRUE(デフォルト)なら、生成された型の型コマンドはサブコマンド(型メソッド)を持ちます。FALSEなら型コマンドはサブコマンドを持たず、最初の引数をインスタンスの名前としてインスタンスを生成する機能だけを提供します。
このプラグマと-hasinstancesを両方同時にFALSEにすることはできません。
- -hasinstances flag
TRUE(デフォルト)なら、生成された型は、インスタンスに関連した様々な機能と、型のインスタンスを生成するのに使われるcreateという名前の型メソッドを持ちます。もしFALSEなら持ちません。
このプラグマと-hastypemethodsを両方同時にFALSEにすることはできません。
- -hasinfo flag
TRUE(デフォルト)なら、生成された型のインスタンスは、インスタンスの内省に使われるinfoというインスタンスメソッドを持ちます。infoメソッドは後述しています。FALSEなら持ちません。
- -simpledispatch flag
このプラグマは 頻繁に利用される抽象データ型(たとえばスタックとキュー)をより効率的にするために、簡単にすることを目的としています。FALSE(デフォルト)なら、インスタンスメソッドは普通にディスパッチされます。TRUEなら、より高速なディスパッチ機構が代わりに使われます。スピードの代償として、-simpledispatch yesにすると、次のような制限があります。
・メソッドは委譲できません。
・uplevelとupvarは期待したようには動きません。呼び出し側のスコープは1レベルでなく2レベル上です。
・オプションを操作するメソッド(cget、configure、configurelist)は本当にちょっとだけ遅いです。
- expose comp
- expose comp as method
廃止予定。コンポーネントcompをパブリックにするにはcomponentの-publicオプションを使用してください。
- onconfigure name arglist body
廃止予定。optionの-configuremethod を代わりに使用してください。
バージョン0.95時点での次のような定義は
option -myoption
onconfigure -myoption {value} {
# Code to save the option's value
}
次のように実装されます。
option -myoption -configuremethod _configure-myoption
method _configure-myoption {_option value} {
# Code to save the option's value
}
- snit::widget name definition
このコマンドは指定されたnameでSnitメガウィジェット型を定義します。definitionは snit::typeと同じように定義されますが、snit::widgetはsnit::typeと次の点で異なっています。
- 全てのsnit::widgetのインスタンスは自動的に生成されたコンポーネントhullを持ちます。hullは普通のTkフレームウィジェットです。他のメガウィジェットの一部として生成されたウィジェットは、このhullの中に作成されます。
hullコンポーネントは、最初は要求されたウィジェット名で作成され、それからSnitがちょっとゴニョゴニョして、そのhullコンポーネントをリネームし、自身のインスタンスコマンドを適切にインストールします。hullコンポーネントの新しい名前はhullという名前のインスタンス変数に保存されます。
- インスタンスの名前は正当なTkのウィンドウ名であり、かつ、親ウィンドウが存在していなければなりません。
snit::widget定義ではsnit::type定義で使用可能なステートメントを含むことが出来ます。また、それに加えて次のものを含むこともできます。
- widgetclass name
snit::widgetのウィジェットクラスをデフォルトの値を上書きしてnameに設定する。詳細はTkオプションデータベースを見てください。
- hulltype type
snit::widgetのhullとして使われるウィジェットの種類を決定します。typeはframe(デフォルト)、toplevel、labelframe、完全修飾名のtk::frame、tk::toplevel、tk::labelframeを設定できます。または、もし可能ならば、同等のTileウィジェットの、ttk::frame、ttk::toplevel、ttk::labelframeも設定できます。実際には、-classオプションをサポートしていれば、snit::hulltypes変数にその名前をlappendすることで どのウィジェットでもhullウィジェットとして使うことが出来ます。
- snit::widgetadaptor name definition
このコマンドは指定されたnameでSnitメガウィジェット型を定義します。snit::widgetとの違いは、インスタンスのhullコンポーネントが自動的に作成されない点で、hullはコンストラクタで生成され、installhullコマンドを使ってインストールされます。一度hullがインストールされると、そのインスタンスコマンドはリネームされ、普通のsnit::widgetとして置き換えられます。オリジナルのコマンドはインスタンス変数hullを通じて再びアクセス可能です。
一般的に snit::widgetadaptor のhullウィジェットの widget classを変更するのは不可能ということに 注意してください。
どうやってsnit::widgetadaptorがオプションデータベースとやりとりしているのかという情報は、Tkオプションデータベースを見てください。
- snit::typemethod type name arglist body
既存のtypeのための新しい型メソッドを定義する(または、既存の型メソッドを再定義する)。
- snit::method type name arglist body
既存のtypeのための新しいインスタンスメソッドを定義する(または既存のインスタンスメソッドを再定義する)。
委譲されたインスタンスメソッドは再定義できない点に注意してください。
- snit::macro name arglist body
指定されたname arglist bodyでSnitマクロを定義します。マクロは 新しい型とウィジェット定義文を定義するのに使われます。
マクロとは単純に、型とウィジェット定義をコンパイルするためのスレーブインタプリタで定義された、Tclプロシージャです。従って、マクロは全ての型とウィジェット定義文へアクセスできます。詳細はマクロとメタプログラミングを見てください。
マクロnameは 他の標準のTclコマンドや他のSnitの型とウィジェット定義文と同じようにはできません。例えば、methodまたはdelegate文、または標準のset、list、stringコマンドを再定義することはできません。
- snit::compile which type body
Snitは定義文をTclスクリプトに「コンパイル」することで型、ウィジェット、ウィジェットアダプタを定義します。このスクリプトは、実際に新しい型を定義するTclインタプリタで実行されます。
このコマンドは「コンパイラ」をさらけ出します。指定されたtype(ここではtype、widget、widgetadaptorのどれか)のbody定義が与えられると、snit::compileは二つの要素のリストを返します。最初の要素は完全修飾名で、二つ目の要素はスクリプト定義です。
snit::compileは、Snitが生成したコードに追加処理が終われなければならないときに便利です。例えば、TclDevKitコンパイラに通すようなときなど便利です。加えて、返り値のスクリプトは".tcl"ファイルに保存して、アプリケーションやライブラリの一部として型を定義することができます。
このようにして、アプリケーションの起動時のコンパイルのオーバーヘッドを減らすことができます。コンパイル時と同じバージョンのSnitがランタイムとして使われていなければならない点に注意してください。
型コマンド †
型またはウィジェット定義は型コマンドを作成します。これはその型のインスタンスを作成するのに使われます。型コマンドの形式は次のようになっています。
標準的な型メソッド †
型定義での型メソッドに加えて、全ての型とウィジェットコマンドは普通少なくとも次のサブコマンドを持っています。
- $type create name? option value ...?
指定されたnameをつけた型のインスタンスを新しく作成し、型のコンストラクタを呼び出します。でsnit::typeは、もしnameが完全修飾名でなければ、それはsnit::typeが呼び出された名前空間中にあると推測されます。このメソッドは完全修飾名を返します。
snit::widgetとsnit::widgetadaptorの場合、nameは有効なウィジェット名でなければなりません。このメソッドはウィジェット名を返します。
nameが他の型メソッドの名前と衝突しない限りは、createキーワードは省略することができます。ただし、型定義がdelegate typemethod *を含んでいるか、-hasinstancesがFALSEに設定されている場合はできません。
もしnameが%AUTO%という文字列を含んでいると、それは$type$counter という文字列に置き換えられます。ここで$typeは型名で$counterは%AUTO%がこの型で使われるたびに増える数値です。
デフォルトでは、nameに続く引数はオプションの名前と、その値のリストになります。しかしながら、型のコンストラクタは異なる引数リストを設定することができます。
Snit V0.95以後は、もしnameが既存のコマンド名と同じ場合、createはエラーを投げます。すでにsnit::widgetとsnit::widgetadaptorではこのような動作になっていたことに注意してください。-canreplace プラグマを使うことで既存の動作を置き換えることができます。
- $type info typevars ? pattern?
型の型変数(Snitの内部変数を除く)のリストを返します。全ての変数の名前は完全修飾されます。
もしpatternが与えられるとstring matchパターンが使われるように、パターンにマッチした名前だけが返ります。
- $type info typemethods ? pattern?
型の型メソッドのリストを返します。もし型が階層的な型メソッドを持っているなら(ローカル定義されていようが委譲されていようが) 最初のトークンだけがリストに含まれます。
もし型定義がdelegate typemethod *を含んでいる場合、そのリストは(少なくとも一回呼び出されて型メソッドキャッシュにある)暗黙的に委譲された型メソッドの名前のみ含むでしょう。
もしpatternが与えられるとstring matchパターンが使われるように、パターンにマッチした名前だけが返ります。
- $type info args method
型のmethodの引数の名前のリストを返します。
このメソッドは委譲された型メソッドには適用できません。
- $type info body method
型メソッドmethodのボディを返します。このメソッドは委譲された型メソッドには適用できません。
- $type info default method aname varname
methodの引数のanameがデフォルト値を持っているかどうか真偽値を返します。持ってる場合はTRUE、持ってない場合はFALSE。もし引数がデフォルト値を持ってる場合、変数varnameにその値が代入されます。
- $type info instances ? pattern?
型のインスタンスのリストを返します。snit::typeでは、完全修飾された名前のリストです。snit::widgetでは、Tkウィジェットの名前のリストです。
もしpatternが与えられるとstring matchパターンが使われるように、パターンにマッチした名前だけが返ります。
Snit 1.x 非互換:Snit 1.xでは階層的な型メソッドの複数単語名は返り値に含まれます。
- $type destroy
型のインスタンス、型の名前空間、型コマンド自身を破棄します。
インスタンスコマンド †
Snitのtype、widgetの型メソッドcreateは、型のオブジェクトを生成します。
各オブジェクトは固有の名前を持っていて、その名前はまた、Tclのコマンドでもあります。このコマンドはオブジェクトのメソッドとデータにアクセスするのに使われます。次のような構文になります。
- $object method args...
methodは 標準的なインスタンスメソッド のいずれか、または型定義で定義されたインスタンスメソッドのいずれかです。それに続くargsは選択されたmethodによって異なります。
標準的なインスタンスメソッド †
型定義で委譲されたインスタンスメソッド、ローカル定義されたインスタンスメソッドに加えて、全てのSnitオブジェクトは最低限次のサブコマンドも持ちます。
- $object configure ? option ? ? value ? ...
新しい値を一つ以上のオプションに割り当てます。もし引数がオプション(option)の名前一つだけの場合、Tkウィジェットがするように、オプションの説明のリストを返します。もし引数無しで呼び出されると、Tkウィジェットがするように、全てのオプションの説明のリストを返します。
警告:委譲されたオプションの場合、委譲されたコンポーネントが同種の情報を返すconfigureメソッドを持っている場合のみ、情報を取得できます。
注意:Snitは、型が最低でも一つオプションを持っている場合のみこのメソッドを定義します。
- $object configurelist optionlist
configureと同じですが、引数はオプションとその値のリスト一つだけです。これは型コンストラクタでは特に便利ですが、どこでも使うことができます。
注意:Snitは、型が最低でも一つオプションを持っている場合のみこのメソッドを定義します。
- $object cget option
オプションの値を返します。
注意:Snitは、型が最低でも一つオプションを持っている場合のみこのメソッドを定義します。
- $object destroy
destructorを呼び出し、全ての関連するメモリを解放して、オブジェクトを破棄します。
注意:destroyメソッドはsnit::widgetとsnit::widgetadaptorのオブジェクトでは定義されません。これらのインスタンスは、普通のウィジェットのようにTkのdestroyコマンドを使って破棄します。
- $object info type
インスタンスの型を返します。
- $object info vars ? pattern ?
オブジェクトのインスタンス変数(Snitの内部変数は除く)のリストを返します。変数の名前は完全修飾されます。
もしpatternが与えられるとstring matchパターンが使われるように、パターンにマッチした名前だけが返ります。
- $object info typevars ? pattern ?
オブジェクトの型の型変数(Snitの内部変数は除く)のリストを返します。変数の名前は完全修飾されます。
もしpatternが与えられるとstring matchパターンが使われるように、パターンにマッチした名前だけが返ります。
- $object info typemethods ? pattern ?
型の型メソッドのリストを返します。もし型が階層的な型メソッドを持っているなら(ローカル定義されていようが委譲されていようが) 最初のトークンだけがリストに含まれます。
もし型定義がdelegate typemethod *を含んでいる場合、そのリストは(少なくとも一回呼び出されて型メソッドキャッシュにある)暗黙的に委譲された型メソッドの名前のみ含むでしょう。
もしpatternが与えられるとstring matchパターンが使われるように、パターンにマッチした名前だけが返ります。
Snit 1.x 非互換:Snit 1.xでは、階層化された型メソッドの(複数の単語の)完全な名前が返り値に含まれます。
- $object info options ? pattern ?
オブジェクトのオプションの名前のリストを返します。これは常に
ローカルのオプションと明示的に委譲されたオプションを含んでいます。それに加えて、もし未知のオプションが委譲されていて、その委譲されたコンポーネントがTkウィジェットのように$object configureで値を返すのならば、使用可能な未知のオプションも返り値に含まれます。
もしpatternが与えられるとstring matchパターンが使われるように、パターンにマッチした名前だけが返ります。
注意:返り値は、同じ型でもインスタンスごとに違うことがあるかもしれません。なぜなら、コンポーネントオブジェクトの型は、インスタンスごとに変えることができるからです。
- $object info methods ? pattern ?
インスタンスのメソッドの名前のリストを返します。もし型が階層的な型メソッドを持っているなら(ローカル定義されていようが委譲されていようが) 最初のトークンだけがリストに含まれます。
もし型定義がdelegate typemethod *を含んでいる場合、そのリストは(少なくとも一回呼び出されて型メソッドキャッシュにある)暗黙的に委譲された型メソッドの名前のみ含むでしょう。
もしpatternが与えられるとstring matchパターンが使われるように、パターンにマッチした名前だけが返ります。
Snit 1.x 非互換:Snit 1.xでは、階層化された型メソッドの(複数の単語の)完全な名前が返り値に含まれます。
- $object info args method
インスタンスのmethodの引数の名前のリストを返します。
このメソッドは委譲された型メソッドには適用できません。
- $object info body method
インスタンスのメソッドmethodのボディを返します。このメソッドは委譲された型メソッドには適用できません。
- $object info default method aname varname
methodの引数のanameがデフォルト値を持っているかどうか真偽値を返します。持ってる場合はTRUE、持ってない場合はFALSE。もし引数がデフォルト値を持ってる場合、変数varnameにその値が代入されます。
オブジェクトコード中で使用するコマンド †
Snitは オブジェクトコード中で使用できる 次のコマンドを定義しています。つまり、型メソッド、インスタンスメソッド、コンストラクタ、デストラクタ、onconfigure処理、oncget処理、プロシージャにおいて使うことができます。このコマンドは::snit::名前空間中には存在せず、型とともに作成され、名前空間の装飾なしに使うことができます。
- myvar name
インスタンス変数の名前を与えると、その完全修飾名を返します。変数を他のオブジェクトに渡すときに使ってください。例えば、Tkのラベルウィジェットの-textvariableなどに渡す時など。
- mytypevar name
型変数の名前を与えると、その完全修飾名を返します。変数を他のオブジェクトに渡すときに使ってください。例えば、Tkのラベルウィジェットの-textvariableなどに渡す時など。
- from argvName option ? defvalue ?
fromコマンドは オプションの値をオプションと値のリスト(例えば型のコンストラクタで渡されるリストのような)から抜き出します。argvNameはそのリストの変数の名前でなければなりません。optionは指定されたオプションの名前です。
fromコマンドはoptionをオプションリストから探し、もし見つかれば、そのオプションとその値をリストから削除し、その値を返します。もしoptionが見つからなければ、defvalueを返します。もしオプションがローカル定義されたオプションで、defvalueが設定されていなければ、型定義で設定されたオプションのデフォルト値が返ります。
- installhull using widgetType args...
- installhull name~
snit::widgetadaptorのコンストラクタはオブジェクトのhullコンポーネントになるウィジェットを作成しなければなりません。 そのウィジェットは、このコマンドを使いhullコンポーネントとしてインストールされます。インストールされたウィジェットの名前は"$win"でなければならない点に注意してください。このコマンドは二つの形式を持っています。
最初の形式では、hullウィジェットを作成するのに、widgetTypeとargs...(つまり、ハードコーディングされたオプションリスト) を設定します。この形式が用いられるとinstallhullはhullウィジェットを作成し、Tkオプションデータベースからhullに委譲されたオプションを初期化します。
二番目の形式では、hullウィジェットは既に作成されています。その名前は"$win"でなければならない点に注意してください。この場合、hullに委譲されたオプションはTkオプションデータベースには問い合わせをしない点に注意してください。
長い方の形式が好ましいです。しかし、短いほうの形式はプログラマがどこでウィジェットを作成してもよいので、便利なときもあります。例えば、BWidgetのタブノートブックやページマネージャーウィジェットによって作成された"page"ウィジェットを改編するのに使うことができます。
snit::widgetadaptorとオプションデータベースに関する詳細はTkオプションデータベースを見てください。
- variable name
普通は、インスタンス変数は型定義においてオプションやメソッドなどと一緒に定義されます。そのようなインスタンス変数は自動的に全てのインスタンスコードで可視になります(例えばメソッドのボディ)。しかしながら、インスタンスコードはvariableコマンドを使って、型定義には現れないインスタンス変数を宣言し、そしてまた、他の名前空間から変数を現在のスコープに持ってくることができます。
ほとんどの場合、型定義で全てのインスタンス変数を定義し、メソッドなどの中ではそれらの宣言を省略するのが最もわかりやすいです。
これは 標準のTcl::variableコマンドの、インスタンス用の特別バージョンです。
- typevariable name
普通は、型変数は型定義においてインスタンス変数と一緒に定義されます。そのような型変数は自動的に型の全てのコードで可視になります。しかしながら、型メソッド、インスタンスメソッドなどはtypevariableを使って、型定義には現れない型変数を宣言することができます。
ほとんどの場合、型定義で全ての型変数を定義し、メソッドや型メソッドなどの中ではそれらの宣言を省略するのが最もわかりやすいです。
- varname name
廃止予定。myvarを代わりに使用してください。
インスタンス変数の名前を与えると、その完全修飾名を返します。変数を他のオブジェクトに渡すときに使ってください。例えば、Tkのラベルウィジェットの-textvariableなどに渡す時など。
- typevarname name
廃止予定。mytypevarを代わりに使用してください。
型変数の名前を与えると、その完全修飾名を返します。変数を他のオブジェクトに渡すときに使ってください。例えば、Tkのラベルウィジェットの-textvariableなどに渡す時など。
- codename name
廃止予定。myprocを代わりに使用してください。
proc名(型、インスタンスのメソッドではない)を与えられると、コールバックに渡すのに最適な完全修飾名を返します。
コンポーネントと委譲 †
オブジェクトが他のオブジェクトを含んでいる時、例えば、ツールバーがボタンを含んでいたり、GUIオブジェクトがデータベースを参照する他のオブジェクトを含んでいる場合、含まれたオブジェクトはコンポーネントと呼ばれます。Snitオブジェクトによって所有されているコンポーネントを取り扱う標準的な方法は、それらをcomponentを使って宣言することです。componentはコンポーネントのインスタンス変数を作成します。次の例では、dogオブジェクトはtailオブジェクトを所有しています。
snit::type dog {
component mytail
constructor {args} {
set mytail [tail %AUTO% -partof $self]
$self configurelist $args
}
method wag {} {
$mytail wag
}
}
snit::type tail {
option -length 5
option -partof
method wag {} { return "Wag, wag, wag."}
}
tailオブジェクトの名前はインスタンス変数に保存されるので、簡単にメソッドにアクセスすることができます。
installコマンドは、コンポーネントの作成とインストールの別の方法を提供します。
snit::type dog {
component mytail
constructor {args} {
install mytail using tail %AUTO% -partof $self
$self configurelist $args
}
method wag {} {
$mytail wag
}
}
snit::typeにとっては、上記の二つの方法は同じです。snit::widgetとsnit::widgetadaptorでは、installコマンドはTkオプションデータベースに問い合わせることでウィジェットのオプションを適切に初期化します。
上記の例ではdogオブジェクトのwagメソッドは、単純にtailコンポーネントのwagメソッドを呼び出していました。OO用語ではこれは委譲(デリゲーション)と呼ばれています。Snitは委譲するための簡単な方法を提供しています。
snit::type dog {
delegate method wag to mytail
constructor {args} {
install mytail using tail %AUTO% -partof $self
$self configurelist $args
}
}
型宣言中のdelegate文は、暗黙的に、コンポーネントの名前を保存するためにインスタンス変数mytailを定義します。(とはいえ、componentを使って明示的にそれを宣言するのはよいことです。)そして、dogオブジェクトのwagメソッドを定義し、mytailコンポーネントに委譲します。
お望みならほかの未知のメソッドも全て、指定されたコンポーネントに委譲することができます。
snit::type dog {
delegate method * to mytail
constructor {args} {
set mytail [tail %AUTO% -partof $self]
$self configurelist $args
}
method bark { return "Bark, bark, bark!" }
}
この場合、dogオブジェクトはそれ自身のbarkメソッドを処理しますが、wagはmytailにパスされるでしょう。dogにもtailにも存在していないメソッドの呼び出しは単純にエラーになります。
オプションの委譲はメソッドの委譲に似ていますが、Tkオプションデータベースと相互作用する点は異なります。
型コンポーネントと委譲 †
型コンポーネントとインスタンスコンポーネントの関係は、型変数とインスタンス変数の関係や、型メソッドとインスタンスメソッドの関係と同じです。ちょうどインスタンスコンポーネントがコマンド名を保持しているインスタンス変数であるように、型コンポーネントはコマンドの名前を保持している型変数です。要するに、型コンポーネントとは、 その型の全てのインスタンスで共有されるコンポーネントのことです。
コンポーネントと委譲で説明したとおり、delegate methodをインスタンスコンポーネントにメソッドを委譲するのに使えるのと同じく、型メソッドを型コンポーネントに委譲するのにdelegate typemethodを使うことが出来ます。
Snit 0.95 では、delegate methodはメソッドをインスタンスコンポーネント、型コンポーネントの両方に委譲することができたということにも注意してください。
Tkオプションデータベース †
このセクションでは、どのようにSnitがTkオプションデータベースと相互作用し、オプションデータベースの情報を読み取ったり利用するかということについて説明します。Effective Tcl/Tk Programmingと同じく、Welch et alによる Practical Programming in Tcl and Tkがオプションデータベースのよい手引きです。
Snitは、ウィジェットの開発者がSnitで適切に振舞えば、大抵の場合はオプションデータベースに関してうまく動くように設計されています。このセクションの本文ではSnitが何を必用としているかについて詳しく扱います。次のリストは参考のために必用なことの概要です。
- もしsnit::widgetのデフォルトのウィジェットクラスが望んでいるものと異なる場合は、ウィジェットの定義でwidgetclassを使って明示的に設定してください。
- オプションを定義するか、委譲したときに、デフォルトの値が望んでいるものと異なる場合は、リソースとクラス名を明示的に指定してください。
- snit::widgetadaptorではinstallhull usingを使ってhullをインストールしてください。
- 他のコンポーネントをインストールするにはinstallを使ってください。
Tkウィジェットとオプションデータベースの相互作用は複雑です。Snitとオプションデータベースも複雑です。
ウィジェットクラスの設定:全てのTkウィジェットはウィジェットクラスを持っています。Tkウィジェットでは、ウィジェットクラスの名前はウィジェットの型名の一文字目を大文字にしたものです。例:buttonウィジェットのウィジェットクラスは"Button"です。
同じように、snit::widgetのデフォルトのウィジェットクラスは、最初の一文字が大文字の制限の無い型名になります。例えば次のウィジェットクラスの場合は
snit::widget ::mylibrary::scrolledText { ... }
"ScrolledText"になります。ウィジェットクラスはsnit::widget定義の中で明示的にwidgetclass文を使って設定することができます。
ウィジェットが-classオプションをサポートしていれば、そのウィじぇとクラス名を変更するhulltypeを使うことができます。先述したhulltypeコマンドの説明を見てください。ユーザーは-classオプションをウィジェットに渡すことも出来ます。
snit::widgetadaptorのウィジェットクラスはだたのhullウィジェットのウィジェットクラスです。
hullウィジェットが-classをサポートしている場合を除いては、
これを変更することはできないので、そのような場合は大体snit::widgetのほうがsnit::widgetadaptorよりも良いです。
オプションのリソース名とクラス名の設定:Tkでは、全てのオプションは三つの名前を持っています(オプション名、リソース名、クラス名)。オプション名はハイフンではじまり全て小文字です。それはウィジェットの作成時、configureとcgetコマンドで使われます。
リソース名とクラス名は、Tkオプションデータベースに問い合わせてオプションをデフォルト値に初期化するのに使われます。リソース名は大抵はオプション名からハイフンを取り除き、単語の区切りごとに大文字にしたものです。クラス名は大抵はリソース名の最初の文字を大文字にしたものですが、必ずしもそうであるとは限りません。例えば、これはtextウィジェットのいくつかのオプション名、リソース名、クラス名です。
-background background Background
-borderwidth borderWidth BorderWidth
-insertborderwidth insertBorderWidth BorderWidth
-padx padX Pad
ちょっと見ると、リソースとクラスの名前はオプションの名前から推測できることがわかりますが、ただし、常にそうであるとはかぎりません。
Snitのオプションも、リソースとクラスの名前を持っています。デフォルトでは、これらの名前は先述のルールに従います。リソース名はオプション名からハイフンを除き、クラス名はリソース名の一文字目を大文字にしたものです。これはローカル定義されたオプションと明示的に委譲されたオプションに当てはまります。
snit::widget mywidget {
option -background
delegate option -borderwidth to hull
delegate option * to text
# ...
}
この場合、ウィジェットのクラス名は"Mywidget"です。そしてウィジェットは次のオプションを持っています。-background(ローカル定義)、-borderwidth(明示的に委譲された)、その他のオプションはおそらくTkのtextウィジェットである"text"というコンポーネントに委譲されています。もしそうなら、mywidgetはtextウィジェットと全て同じオプションを持っています。オプション、リソース、クラスの名前は次のとおりです。
-background background Background
-borderwidth borderwidth Borderwidth
-padx padX Pad
ローカル定義されたオプションである-backgroundが標準のTkの-backgroundオプションと同じ三つの名前を持っているところに注目してください。そして、暗黙的にtextコンポーネントから委譲された-padの三つの名前が、textウィジェットと同じになっているところにも注目してください。
その一方で、-borderwidthは標準とは異なるリソースとクラスの名前を持っています。中の文字の"width"の一文字目が大文字になっていません。整合性をとるために、これは次のようにするべきです。
snit::widget mywidget {
option -background
delegate option {-borderwidth borderWidth} to hull
delegate option * to text
# ...
}
クラス名は期待したとおりに"BorderWidth"になります。
また、mywidgetが-padxと-padyをhullに委譲していると仮定してみてください。この場合、リソース名とクラス名の両方とも明示的に設定されなければなりません。
snit::widget mywidget {
option -background
delegate option {-borderwidth borderWidth} to hull
delegate option {-padx padX Pad} to hull
delegate option {-pady padY Pad} to hull
delegate option * to text
# ...
}
オプションデータベースへの問い合わせ:widgetclassとオプション名を上記のように設定したら、インスタンスが作成されるごとに Snitはオプションデータベースに問い合わせをし、 大抵は
オプションデータベースへの問い合わせは、適切に行うでしょう。 このセクションの残りはその泥臭い詳細について述べます。
ローカル定義されたオプションの初期化:snit::widgetのインスタンスが作成された時、そのローカル定義されたオプションは次のようにして初期化されます。各オプションのリソースとクラスの名前がTkオプションデータベースに問い合わせるために使われます。もし、そのリソースが空でなければ、その値がオプションのデフォルトとして使われますが、そうでなければ、型定義でハードコーディングされたデフォルト値が使われます。どちらの場合でも、デフォルトの値は呼び出し側で上書きすることができます。例えば次のとおりです。
option add *Mywidget.texture pebbled
snit::widget mywidget {
option -texture smooth
# ...
}
mywidget .mywidget -texture greasy
ここ、-textureは普通に"smooth"に設定されます。しかし、
オプションデータベースにそのオプションが登録されているので、そのデフォルトは"pebbled"に設定されます。しかしながら、呼び出し側で明示的にデフォルト値を上書きしているので、新しいウィジェットでは"greasy"になるでしょう。
hullに委譲されたオプションの初期化:snit::widgetのhullはウィジェットで、そのクラスはそれ自身のオプションデータベースに問い合わせて設定されます。唯一の例外は、異なる名前で委譲されたオプションに関係しています。次のコードを考えてみてください。
option add *Mywidget.borderWidth 5
option add *Mywidget.relief sunken
option add *Mywidget.hullbackground red
option add *Mywidget.background green
snit::widget mywidget {
delegate option -borderwidth to hull
delegate option -hullbackground to hull as -background
delegate option * to hull
# ...
}
mywidget .mywidget
set A [.mywidget cget -relief]
set B [.mywidget cget -hullbackground]
set C [.mywidget cget -background]
set D [.mywidget cget -borderwidth]
それでは質問です。A, B, C, Dの変数の値は何でしょうか。
Aの値は"sunken"です。hullはウィジェットクラスが"Mywidget"の Tkフレームです。自動的にオプションデータベースに問い合わせて、この値を取り出します。-reliefオプションは暗黙的にhullに委譲されたので、Snitは何もしていません。
Bの値は"red"です。hullは-reliefで値を取り出したように、自動的にその-backgroundオプションの"green"を取り出します。しかしながら、Snitは-hullbackgroundがhullの-backgroundオプションにマップされていることを知っているので、オプションデータベースに-hullbackgroundを問い合わせ、"red"を取得し、それに合わせてhullをアップデートします。
Cの値も"red"です。-backgroundは暗黙的にhullに委譲されているので、-hullbackgroundの取得と同じになります。この場合は普通の委譲ではない点に注意してください。普通は-backgroundはおそらく明示的に他のコンポーネントに委譲されているでしょう。
(訳注:BとCの説明は逆のような気がする)
Dの値は"5"です。考えるまでも無いことだと思うかもしれませんが、
上記のルールでは、-borderwidthのリソース名は"borderwidth"に設定されます、しかしながら、オプションデータベースへ"borderWidth"として登録しているところに注目してください。-relief同様に、Snitが何かする前に、hullはその-borderwidthオプションの値を取得します。 そのオプションは、自身の名前で委譲されているので、Snitは正しいことが行われていると推測し、これ以上何もおこないません。
snit::widgetadaptorでは、このようなケースは少し異なります。ウィジェットアダプタはhullのウィジェットクラスを保持し、Snitによってhullは自動的に作成されません。その代わり、snit::widgetadaptorはinstallhullをコンストラクタで呼び出さなければなりません。普通の方法では次のようになります。
snit::widgetadaptor mywidget {
# ...
constructor {args} {
# ...
installhull using text -foreground white
#
}
#...
}
この場合では、installhullコマンドは次のようなコマンドでhullを作成します。
set hull [text $win -foreground white]
hullはtextウィジェットで、そのウィジェットクラスは"Text"になります。snit::widgetのhullと同じように、Snitは自動的にその普通のオプションの値を全て取得します。異なる名前で委譲されたオプションは同じようにしてオプションデータベースから初期化されます。
他のコンポーネントに委譲されたオプションの初期化:hullでないコンポーネントは二つの方法でオプションデータベースに対して適合されます。一つ目は、コンポーネントウィジェットはまだウィジェットなので、一般的な方法でオプションデータベースから初期化されます。二つ目は、installコマンドを使ってコンポーネントに委譲された全てのオプションをオプションデータベースに問い合わせ、コンポーネントはそれに応じて初期化されます。
オプションデータベースのサポートがSnitに追加される以前は、単純にコンストラクタでコンポーネントを作成し、そのコマンド名をコンポーネントの変数に格納するという、一般的な方法で作成していました。
snit::widget mywidget {
delegate option -background to myComp
constructor {args} {
set myComp [text $win.text -foreground black]
}
}
この方法の欠点は、Snitがコンポーネントを適切に初期化する機会を持っていないことです。それゆえ、次のようなアプローチが今は使われています。
snit::widget mywidget {
delegate option -background to myComp
constructor {args} {
install myComp using text $win.text -foreground black
}
}
installコマンドは次のようなことをします。
- installコマンドで明示的に含まれたオプションのリストを作成します(この場合は-foreground)。
- 指定されたコンポーネントに明示的に委譲された全てのオプションをオプションデータベースに問い合わせます。
- オプションデータベースから取得したオプションとその値のリストを挿入した後に指定されたコマンドでコンポーネントを作成します。このようにして、明示的に含まれたオプション(-foreground)はオプションデータベースから読み込まれた値を上書きします。
- もしウィジェット定義で、delegate option *を使って、コンポーネントにオプションを暗黙的に委譲していたら、コンポーネントのオプションの全てのリストを取得するために、Snitは新たに作成したコンポーネントのconfigureメソッドを呼び出します。ここからSnitは明示的にinstallコマンドで含まれず、暗黙的にコンポーネントに委譲されたオプションのリストを構築します。Snitは、そのようなオプションの全てを オプションデータベースに問い合わせ、適切にコンポーネントを設定します。
非ウィジェットコンポーネント:オプションデータベースはsnit::typeのために絶対に問い合わせされません。なぜなら、それは既知のTkウィジェット名を問い合わせられるだけだからです。しかし、snit::widgetは非ウィジェットコンポーネントを持つことが出来ます。そして、もしオプションがこれらのコンポーネントに委譲されていて、これらのコンポーネントをインストールするのにinstallコマンドが使われていたら、それらのオプションは、ウィジェットコンポーネントのようにオプションデータベースから初期化されます。
マクロとメタプログラミング †
snit::macroコマンドはSnitクラスでのメタプログラミングをある程度可能にします。例えば、set/getメソッドを持ったインスタンス変数である、プロパティを定義したいとします。あなたのコードはこのようになるでしょう。
snit::type dog {
variable mood happy
method getmood {} {
return $mood
}
method setmood {newmood} {
set mood $newmood
}
}
プロパティごとに9行使っています。snit::macroを使って次のように定義することも出来ます。
snit::macro property {name initValue} {
variable $name $initValue
method get$name {} "return $name"
method set$name {value} "set $name \$value"
}
snit::macroは、型とウィジェットの定義をコンパイルするスレーブインタープリタにある、ただのTclプロシージャだということに注目してください。結果として、型とウィジェットを定義するために使われる全てのコマンドにアクセスできます。
この新しいマクロによって、一行でプロパティを定義することが出来ます。
snit::type dog {
property mood happy
}
マクロの中では、variableとprocコマンドはTclの標準プロシージャではなく、Snitの型定義コマンドを参照しています。標準のTclコマンドを取得するには、_variableと_procを使用してください。
アプリケーション中の全てのSnitの型とウィジェットをコンパイルのに使われているスレーブインタプリタは一つだけなので、マクロ名が衝突する可能性があります。
Snitを使って再使用可能なパッケージを書いていて、snit::macroを使っているなら、それらをあなたのパッケージの名前空間で定義してください。
snit::macro mypkg::property {name initValue} { ... }
snit::type dog {
mypkg::property mood happy
}
これはアプリケーションの作者にとってグローバル名前空間を開けた状態にしておきます。
検証型 †
検証型とは、特定のTclの値を検証するのに使うことができるオブジェクトです。例えば、snit::integerはTclの値が整数かどうか検証するのに使われます。
全ての検証型は検証を行うvalidateメソッドを持っています。このメソッドは検証される値を引数に一つだけ取ります。さらに、もし値が適正であれば何もしませんが、値が不正な場合はエラーを投げます。
snit::integer validate 5 ;# Does nothing
snit::integer validate 5.0 ;# Throws an error (not an integer!)
Snitは検証型の様々な種類を定義しています。それらの全てはsnit::typeとして実装されています。それらはそのまま使うことが出来ます。加えて、それらのインスタンスはパラメータ化された亜種(サブタイプ)として役に立ちます。例えば、確率は0.0から1.0の間の数値です。
snit::double probability -min 0.0 -max 1.0
このサンプルはprobabilityというsnit::doubleのインスタンスを作成します。これは確率の値を検証するのに使うことが出来ます。
probability validate 0.5 ;# Does nothing
probability validate 7.9 ;# Throws an error
検証サブタイプは上記の例のように明示的に定義することができます。ローカル定義されたオプションで-typeが設定されると、それらはまたオンザフライに作成されます。
snit::enum ::dog::breed -values {mutt retriever sheepdog}
snit::type dog {
# Define subtypes on the fly...
option -breed -type {
snit::enum -values {mutt retriever sheepdog}
}
# Or use predefined subtypes...
option -breed -type ::dog::breed
}
先述した動作をするvalidateメソッドを持つオブジェクトは検証型として使うことが出来ます。新しい検証型を定義する方法は 検証型の定義を見てください。
Snitは次の検証型を定義しています。
- snit::boolean validate ? value ?
- snit::boolean name~
Tclの真偽値(1, 0, on, off, yes, no, true, false)を検証します。サブタイプを定義することができますが、オプションがありません。というのは、そうする理由が無いからです。
- snit::double validate ? value ?
- snit::double name ? option value... ?
浮動少数値を検証します。次のオプションでサブタイプを作ることが出来ます。
- -min min
浮動少数の最小値を指定します。値がminより小さければ不正です。
- -max max
浮動少数の最大値を指定します。値がmaxより大きければ不正です。
- snit::enum validate ? value ?
- snit::enum name ? option value... ?
値が列挙リストに含まれているかどうか検証します。基本型はそれ自身ではほとんど役に立ちません。実際は、サブタイプが検証する列挙リストを持ちます。サブタイプは次のオプションで作成されます。
- -values list
適正な値のリストを設定します。もし値がそのリストに含まれていれば、値は適正です。
- snit::fpixels validate ? value ?
- snit::fpixels name ? option value... ?
Tkプログラム専用です。 winfo fpixelsによって認められたすべての形式のスクリーン距離を検証します。サブタイプは次のオプションで作成できます。
- -min min
最小値を指定します。もしminより小さければ値は不正です。バウンドはwinfo fpixelsによって認められた全ての形式で表現できます。
- -max max
最大値を指定します。もしminより大きければ値は不正です。バウンドはwinfo fpixelsによって認められた全ての形式で表現できます。
- snit::integer validate ? value ?
- snit::integer name ? option value... ?
整数値を検証します。サブタイプは次のオプションで作成できます。
- -min min
整数の最小値を指定します。minより値が小さければ不正です。
- -max max
整数の最大値を指定します。minより値が大きければ不正です。
- snit::listtype validate ? value ?
- snit::listtype name ? option value... ?
Tclリストを検証します。サブタイプは次のオプションで作成できます。
- -minlen min
最小のリスト長を指定します。リストの要素がminより少なければ不正です。デフォルトは0です。
- -maxlen max
最大のリスト長を指定します。リストの要素がmaxより多ければ不正です。
- -type type
リスト要素の型を指定します。typeは検証型か検証型のサブタイプの名前でなければなりません。次の例では、-numbersの値は整数のリストでなければなりません。
option -numbers -type {snit::listtype -type snit::integer}
このオプションは、オンザフライに新しい検証型のサブタイプを定義することをサポートしていない点に注意してください。つまり、次のコードは動かないでしょう。
option -numbers -type {
snit::listtype -type {snit::integer -min 5}
}
そのかわりに、明示的にサブタイプを定義してください。
snit::integer gt4 -min 5
snit::type mytype {
option -numbers -type {snit::listtype -type gt4}
}
- snit::pixels validate ? value ?
- snit::pixels name ? option value... ?
Tkプログラム専用です。 winfo pixelsによって認められたすべての形式のスクリーン距離を検証します。サブタイプは次のオプションで作成できます。
- -min min
最小値を指定します。もしminより小さければ値は不正です。バウンドはwinfo pixelsによって認められた全ての形式で表現できます。
- -max max
最大値を指定します。もしminより大きければ値は不正です。バウンドはwinfo pixelsによって認められた全ての形式で表現できます。
- snit::stringtype validate ? value ?
- snit::stringtype name ? option value... ?
Tcl文字列を検証します。基本型はそれ自身ではほとんど役に立ちません。なぜならばTclの値というのは適正な文字列だからです。サブタイプは次のオプションで作成できます。
- -minlen min
文字列の最小の長さを指定します。もしmin文字よりもすくなければ、値は不正です。デフォルトは0です。
- -maxlen max
文字列の最大の長さを指定します。もしmax文字よりも多ければ、値は不正です。デフォルトは0です。
- -glob pattern
string matchのパターンを設定します。もしパターンにマッチしなければ、値は不正です。
- -regexp regexp
正規表現を指定します。もし正規表現にマッチしなければ、値は不正です。
- -nocase flag
デフォルトでは-globと-regexpはどちらも大文字と小文字を区別します。もし-nocaseがTRUEに設定されると、-globと-regexpは大文字と小文字を区別しなくなります。
- snit::window validate ? value ?
- snit::window name
Tkプログラム専用です。 Tkウィンドウの名前を検証します。値はwinfo existsでtrueを返さなければなりません。そうでなければ、値は不正です。snit::windowのサブタイプを定義することが可能ですが、現在のところ特に必用な理由もないので、オプションはありません。
検証型の定義 †
新しい検証型を定義する方法は3つあります。一つ目はSnitの検証型のサブタイプ、二つ目は検証型コマンド、三つ目はSnitによって提供されている検証型に似た本格的な検証型です。Snitの検証型のサブタイプの定義は先述の検証型で説明しました。
その次に簡単な方法は、検証型コマンドとして新しい検証型を作成することです。検証型はvalidateメソッドを持ったシンプルなオブジェクトです。validateメソッドは値を引数に一つだけ取り、もし値が不正ならエラーを投げます。これは簡単なprocで行うことができます。例えば、snit::boolean検証型はこのように実装することができます。
proc ::snit::boolean {"validate" value} {
if {![string is boolean -strict $value]} {
return -code error "invalid boolean \"$value\", should be one of: 1, 0, ..."
}
return
}
このようにして定義された検証型は当然ながらサブタイプ化できません。しかし、多くのアプリケーションにとってはこれで十分です。
最後に、本格的なサブタイプ化できる検証型をsnit::typeのように定義することができます。これはあなたが書くためのスケルトンです。
snit::type myinteger {
# First, define any options you'd like to use to define
# subtypes. Give them defaults such that they won't take
# effect if they aren't used, and marked them "read-only".
# After all, you shouldn't be changing their values after
# a subtype is defined.
#
# For example:
option -min -default "" -readonly 1
option -max -default "" -readonly 1
# Next, define a "validate" type method which should do the
# validation in the basic case. This will allow the
# type command to be used as a validation type.
typemethod validate {value} {
if {![string is integer -strict $value]} {
return -code error "invalid value \"$value\", expected integer"
}
return
}
# Next, the constructor should validate the subtype options,
# if any. Since they are all readonly, we don't need to worry
# about validating the options on change.
constructor {args} {
# FIRST, get the options
$self configurelist $args
# NEXT, validate them.
# I'll leave this to your imagination.
}
# Next, define a "validate" instance method; its job is to
# validate values for subtypes.
method validate {value} {
# First, call the type method to do the basic validation.
$type validate $value
# Now we know it's a valid integer.
if {("" != $options(-min) && $value < $options(-min)) ||
("" != $options(-max) && $value > $options(-max))} {
# It's out of range; format a detailed message about
# the error, and throw it.
set msg "...."
return -code error $msg
}
# Otherwise, if it's valid just return.
return
}
}
で、このようにしてサブタイプ化できる型を作成できます。
Snitの配布物の中にある"validate.tcl"というファイルは全てのSnitの検証型を定義しています。snit::integerとその他の型の完全な実装をそこで見ることができます。自分で検証型を作成するときに参考にすることができます。
注意書き †
もしバグを見つけたり、問題があったり、新しいアイデアなどを思いついたら、SourceForgeのtcllibのトラッカーにそれらを投稿してくれると本当にありがたいです。
http://sourceforge.net/projects/tcllib/
関連するカテゴリーはsnitです。
加えて、Snitのメーリングリストに入りたいと思うかもしれません。詳細は次のページを見てください。
http://www.wjduquette.com/snit
注意しなければならない分野は、他のメガウィジェットパッケージで作られたメガウィジェットを改造した snit::widgetadaptorの使用です。適切なウィジェットの破棄は<Destroy>のバインディングの順序に依存しています。賢明な選択肢は単純にこれをしないことです。
既知のバグ †
ヒストリー †
私の個人的なTclベースのノートブックアプリケーションである Notebook ( http://www.wjduquette.com/notebook を見てください) を開発している間に、私はオブジェクトの集合を書いているのに気がつきました。私は何か特定のオブジェクト指向のフレームワークを使っていませんでした。
私はただ、自分のオブジェクトコマンドのガイドライン (http://www.wjduquette.com/tcl/objects.html を見てください) に従い、いくつかちょっとしたトリックを加えながら、オブジェクトをピュアTclで書いていました。そして、それはうまく動きました。それからすぐに、新しいオブジェクト型ごとに必用な定型コードの量にうんざりするようになりました。
それが一つの理由でした。――退屈は強力なモチベーションです。しかし、その他の理由は、私が全く継承を使っていなくて、それで何も困っていないということに気がついたことです。その代わりに、私は委譲を使っていました。オブジェクトが他のオブジェクトを作り、メソッドをそれらに委譲していました。
そして私は独り言を言いました。「これはだんだんうんざりしてきた……。もっといい方法があるに違いない」。そして、ある日の午後、気まぐれに、Tclのように動くオブジェクトシステムSnitに取り組みはじめました。Snitは継承をサポートしていませんが、委譲は優れています。また、メガウィジェットも簡単に作成できます。
もし何かコメントや提案(またはバグ報告!)があったら気軽にe-mailを私に送ってください。さらに、Snitのめーリングリストがあります。Snitのホームページ( http://www.wjduquette.com/snit )で多くの情報を得ることができます。
クレジット †
Snitはごく初期にはWilliam H. Duquetteによって設計と実装されていました。しかし、多くの功績ははSnitを使って貴重なフィードバックを提供してくれた次の人々のものです。Rolf Ade, Colin McCormack, Jose Nazario, Jeff Godfrey, Maurice Diamanti, Egon Pasztor, David S. Cargo, Tom Krehbiel, Michael Cleverly, Andreas Kupries, Marty Backe, Andy Goth, Jeff Hobbs, Brian Griffin, Donal Fellows, Miguel Sofer, Kenneth Green, and Anton Kovalenko. もし誰か忘れていたらごめんなさい。知らせてくれたらお名前をリストに追加するつもりです。
バグ、アイデア、フィードバック †
このドキュメントと説明しているパッケージには
間違いなくバグや他の問題があるでしょう。それらを次のURLのsnitカテゴリに報告してください。
http://sourceforge.net/tracker/?group_id=12883
またパッケージと、ドキュメントに関して改善案があれば送ってください。
CategoryTclTk