Thu May 20 23:58:38 JST 1999
UNDER CONSTRUCTION :)
技術メモその他あれこれ
僕のところに溜っているだけ、もしくはあまり知られてない、もしくはみんなが知ってるけどあんまし文書として出てない Tcl/Tk 8.0jp (主に UNIX 版)がらみのあれこれをまとめてみました。
configure, make など、いわゆる Compile 一般の FAQ
「Solaris 2.x で patch が当たらないんだけど、なんで?」
Solaris 2.x 附属の patch コマンドを使っているからでしょう。最新の patch コマンドを使えば OK です。
「tk の configure の --enable-xlibHack をつけるとコンパイルできないんですけど」
--enable-xlibHack は、XFree86 3.x でないと動きません。そういうもんです。
その気になれば、X11R6.x でも、動かせます。頑張って下さい B) ちなみに、
こいつをつけると、XIM プロトコルで {PreeditSpot StatusArea} などの
over-the-spot 変換モードを使っている時の IM サーバ用のフォントのロード
(XCreateFontset() の処理)が「劇的」に速くなります。っつーか、明らかに
Xlib の bug で XCreateFontset() が遅くなっているのを直しているのがミソ
なだけです。もっと言うと、XFree86 のソースツリーの xc/lib/X11 に、
unix/CacheLib/omGeneric.c を cp して Xlib を make し直すと、
XCreateFontset() が速くなります :)
日本語入力関係 FAQ
「漢字入力ができない!」
環境変数 XMODIFIERS を、"@im=none" としてると、Tk は XMODIFIRES が設定
されているという理由だけで XIM プロトコルを使おうとします。が、"使う
IM は無いよ" と Xlib に教えているので IM サーバとお話しません。しかも、
XIM プロトコルの使用と kinput2 プロトコルの使用は exclusive なので、こ
の設定では 「んじゃ代わりに kinput2 プロトコルを使おう」などと Tk は思
いません。だから日本語入力は完全に不可能になります。
というわけで、
将来的には、XMODIFIERS の有無で漢字入力プロトコルを決めるのは止めよう
と思っています。が、現状、これで困った、という例を一例しか知らんので、
いつになるかわかりません B)。
現状、これを回避するのに一番簡単なの
は、X リソースデータベースに tkKanjiConversionProtocol リソースを設定
するか、もしくは環境変数 TK_KCPROTO を設定することです。
追加:
tk8.0.5jp1.7 からは、XMODIFIERS が "@im=none" の場合には kinput プロト
コルを使うように変更されています。
「Solaris 2.x の htt とではうまく使えない」
僕もです。kinput2 とでは当然うまく動くのは確認してるし、xwnmo, VJE で
もうまく動いているとの報告はたくさんあるので、僕としては htt が悪いと
思ってます。なんとかして>Sun.
「XIM 使用時に入力した漢字が文字化けするんですけど」
多分 locale 名の問題です。IM サーバの動いているマシンと Tk が動いてい
るマシンが違っていて、両者で同じ Japanese という locale 名を使っている
とします。この状態で、IM サーバの動いているマシンでの Japanese は SJIS
を指し、Tk が動いているマシンでの Japanese は EUC を指している、という
のは大変ありがちです(例えば、IM サーバが HP-UX, Tk が Solaris の場合な
ど)。
解決方法は、ja_JP.eucJP など、ambiguous でない locale 名を使
用することです。
「あるウィジェットで入力を行なおうとして、キーボードフォーカスを入れる(マウスの 1 ボタンをクリックする)と、しばらく動きが止まるんですけど」
前述の、--enable-xlibHack オプションを付けてなくて、特に遅いマシンで X
サーバを動かしている場合にこうなります。理由は、これまた前述のように、
XCreateFontset() が Xlib の bug のため、不当に遅いからです。
--enable-xlibHack が使用可能である環境なら、これを指定して下さい。
そうでない環境の人は、素直にあきらめるか、Open group (現在の X の元締
め)に文句を言うように B)
「canvas ウィジェットでの入力はどうすればいいの?」
canvas の text アイテムの生成時には全くイベントがバインドされてないの
で、単に作っただけでは、日本語に限らず何にも入力できないことを「まず」
覚えておいて下さい。
で、どうするか、というと、手っ取り早いのは
$tk_library/demos.jp/ctext.tcl を読むことです B)。このデモでは、Kinput
プロトコル、XIM プロトコルそれぞれで日本語入力も可能にしてあります。
「entry ウィジェットで on-the-spot 変換モードを使用したいんだけど」
現状、デフォルトでは出来ません ^^; 誰か entry 用の on-the-spot コール
バックプロシジャ書いて下さい _o_
ちょっと言い訳: なんで出来んかと言
うと、entry には text のように Tag がないからなんですぅ。
その他 Tk にまつわる Tips :)
「"destroy ." を呼んで終了すると、異常に遅いんですけど、なんとかならんか?」
多分、そんなあなたは "." に <Destroy> イベントを bind しているのでしょ
う :) でもって、一度生成した "." の子供は終了するまで destroy しないよ
うなスクリプトを書いているのでしょう :) (もし、ここで "." の子供を破壊
するようなコードであれば、以下に述べることにはとっくに気がついているは
ずだから B)
すべてのウィジェットインスタンスは、bindtag として "." のバインドを引
き継いでいます。したがって、"destroy ." として "." を破壊すると、"."
の子供が破壊される瞬間に、"." の Destroy ハンドラが全ての子供に対して
次々と呼ばれることになります。これは遅いだけでなく、思わぬエラーを引き
起こすことがあります(例えば、一度 unset した変数を何回も unset したり、
テンポラリファイルを何回も消そうとしたり...。逆に、"." の子供を
destroy した瞬間に、"." の Destroy ハンドラが呼ばれてしまって悲しい思
いをするとか)。
こいつを避けるには、ちょっとした工夫をすれば OK で
す。何をするかというと、"destroy ." を行なう前に、「"." を除くすべての
ウィジェットインスタンスの bindtag から、"." を削除する」を行なうわけ
です。方法は各自考えるように B)
フォントの pixel サイズ指定と point サイズ指定
Tk のフォントサイズの指定は、point サイズが基本です。とはいえ、X の漢
字フォントを任意の point サイズで使用しようとすると bitmap resizing さ
れてしまいます。これを防ぎたいなら、サイズを指定する時に負の数を与えま
す。{Courier 14} は 14 ポイントの Courier を指し、{Courier -14} は 14
ピクセルの Courier を指します。混同しないように。
"update" と "update idletasks" の違い
X の描画の完了(例えば pack などによってジオメトリの再計算が発生、その
描画が完了する、など)を待ってから処理を続行させなければならない場合、
"update idletasks" は役にたちません。"update" を使います。マニュアルに、
「何が "update idletasks" を使うべきで、何が "update" を使うべきか」が
明示的に書いてないのが悲しいのですが、"update idletasks" では意図した
結果が得られない場合、迷わず "update" に変えることで問題が解決すること
は良くあります :)
Xlib によるプログラミング経験がある人なら、「Tk での
"update" は確実に XSync() を伴うが、"update idletasks" はそうでない」
と覚えておけば問題ないはずです :)
"tkwait visibility" の落し穴
"tkwait visibility" によって、ある toplevel が表示されるのを待つのは、
常に正しく動くとは限りません。なぜなら、toplevel を生成した瞬間にそれ
が Map されてしまう可能性があるからです。Map されたあとに visivility
が変わるのはそれが他のウィンドウで隠された/iconfy された時になるので、
最悪無限に待ち続けます。特に、toplevel を生成し、その後間を空けて
"tkwait visibility" が発行されるような場合に問題がでやすくなります。
確実に待つなら、toplevel を生成した直後に、まず "wm withdraw" で
Unmap してやって、用意が出来たら
after 100 "wm deiconify .top; update"
tkwait visibility .top
くらいが良いでしょう。after 100 ... が嫌なら、
global topIsMapped
set topIsMapped 0
bind .top <Map> {global topIsMapped; set topIsMapped 1}
wm deiconify .top
while {1} {
update
if {$topIsMapped == 1} {
break
}
}
unset topIsMapped
bind .top <Map> {}
などと大げさに書くこともできます :) またまた、この spin wait が嫌なら、
TclX の select コマンド使ってX の socket discriptor を passive wait す
るとか、まぁいろいろ手はあるはずです。各自考えるように B)