Newsgroups: fj.lang.tcl,fj.archives.answers Subject: [comp.lang.tcl] Tk Toolkit Usage Questions And Answers (1/1) Distribution: fj Followup-To: fj.lang.tcl Reply-To: taguchi@aic.co.jp Expires: Fri Apr 14 00:00:00 JST 1995 Keywords: tk, tcl, expect, extended tcl, wish Archive-name: tk-usage-QnA-j/part01 Version: 1.4-J1.0 Last modified: Fri Mar 24 12:08:12 1995 Posting-Frequency: monthly
From: tja@cpu.com (Thomas J. Accardo)
Newsgroups: comp.lang.tcl,comp.answers,news.answers
Subject: FAQ: comp.lang.tcl Tk Toolkit Usage Questions And Answers (1/1)
Followup-To: comp.lang.tcl
Reply-To: tja@cpu.com (Thomas J. Accardo)
Summary: A regular posting of the comp.lang.tcl Tk Toolkit usage
questions and answers.
Originator: tja@cpu.com
Keywords: tk, tcl, wish
Sender: tja@cpu.com
Expires: Sat, 15 Apr 1995 11:59:59 GMT
Approved: news-answers-request@MIT.EDU
Archive-name: tcl-faq/tk/part1
Posting-Frequency: monthly
Version: 1.5
Last-modified: March 14, 1995
この日本語訳に対するご意見・ご質問・誤りのご指摘などは,訳者まで.
また,その他の詳細な情報については,tcl-faq-j/part00 を参照して下さい.
本FAQは, comp.lang.tcl, comp.answers, news.answersに毎月投稿され, また, ftp.aud.alcatel.com (198.64.191.10)のTclアーカイブの, /tcl/docs ディレクトリからも入手可能です.
他の文書やコードへのポインタなどの, さらに多くのTclに関する情報を得られたいならば, Larry Virden (lvirden@cas.org) の管理するFAQ:
"FAQ: comp.lang.tcl Frequently Asked Questions"
を,ftp.aud.alcatel.comの
/tcl/docs/tcl-faq.part0*.gzから入手するとよいでしょう.
Tclプログラミング言語に関する情報は, Joe Moss (joe@morton.rain.com) の管理する FAQ:
"FAQ: comp.lang.tcl Tcl Language Usage Questions And Answers"
を,ftp.aud.alcatel.comの
/tcl/docs/tcl-faq-usage.gzを入手することをお勧めします.
コメントや助言,本FAQへのコントリビューションは,大歓迎です. どうか,tja@cpu.comまでお送り下さい.
→目次へ
Tcl は,システムにその機能がないならば, 自身で用意した以下の関数とインクルードファイルを用います.
dirent.h limits.h stdlib.h string.h opendir.c strerror.c strstr.c strtol.c strtoul.c strtod.c
→目次へ
tcl 7.3 では,opendir の互換ファイルを削除する変更を行いましょう. そして,-DNO_DIRENT, -DUSE_DIRENT2 を削除すれば,問題は解決します.
→目次へ
Tk は,その ウィジェット立体表示のために, 表示枠のカラー確保のための独自の仕組みを使っています. これが Tk を,"Pseudo Color" ディスプレイ・クラスで, 16 セルのカラーマップのマシン上で実行する際,問題となります.
8 bit プレーンを使えないならば, ディスプレイ・クラスを "StaticColor"にする様に, サーバを "-static" (Xsco) や "-analog" (Xsight) オプション指定で立ち上げるとよいでしょう. これは,カラーマップを完全に読み込みのみとし, 要求された色にできるだけ最も近い色を返すようにします.
この情報は,Keith Amann (Keith_Amann@stortek.com) から寄せられました.
→目次へ
実例をあげるならば,printf("%Ng", double_value)と strtod("+",&terminal) は,誤った結果をもたらします.
→目次へ
→目次へ
→目次へ
openwin -dev "/dev/fb staticvis"こうすれば,静的カラー表示モデルとなり,Tk は,デフォルトよりも良く動作します. 多少,表示が美しくありませんが,モノクロよりは良いでしょう.
→目次へ
→目次へ
→目次へ
From: Robert Nicholson (robert@steffi.demon.co.uk)
これは TCL7.1 と TK3.4 を対象とします.
これは Thomas Funke のエントリです. TCL7.1 の NeXT へのインストール法
tcl7.1 を NeXTSTEP 3.1 にインストールするには,以下のようにします:
CPP='cc -E' ./configure
COMPAT_OBJS = getcwd.o waitpid.o strtod.o tmpnam.o
-Dstrtod=newstrtod -Dtmpnam=newtmpnam
名称変更された関数の定義は,compat/*.c にあります.
全てが正しく動くかどうかをチェックするには,tclsh を起動し, 以下を実行します.
% expr {"0" == "+"}
0
間違えた strtod 関数を用いていたならば,返り値は 1 になり,
深刻なエラーとなります.正確なエラーは無視します.
TK3.4 の NEXTSTEP 3.1 へのインストール法
Tk3.4 の中にも strtod 関数の呼び出しがあるので, 前述の ../tcl-7.1/compat/strtod.o にリンクを張り, AC_FLAGS に -Dstrtod=newstrtod を付け加える必要があります.
注意: Tk の raise 試験は, ウィンドウマネージャに tvtwm を使っていると失敗します. この試験を通すためには,twm や fvwm などに変更する必要があります.
→目次へ
私のところに届いてる知らせによると, 多くの人々が,この本の一部の印字出力で問題を抱えているようです.
古いバージョンの Transcript スプーラ・ソフトウェアには, ページが逆順になった PostScript ファイルの中で, 別の encapsulated PostScript ファイルを扱えないものがあるようです. これらは,ページ構造をごっちゃにする傾向があり, 最初の EPS ファイルのところで,エラーになってしまいます. 第 2 部は,スクリーンダンプを載せるために, 沢山の EPS ファイルが埋め込まれています. もし,このファイルを印字出力できないなら, ページ逆順出力が可能となってるかどうかを見て下さい. もしそうであるならば,利用しているシステムのウィザードに言って, 一時的に不能にしてもらいましょう. これで,出力可能になる筈です. あるいは,あるいは,スプールソフトウェアを経由せずに, 直接プリンタに送る手を考えるのもよいでしょう (例えば,プリンタの継ってるシリアルポートに,直接 cat してしまうとか).
他にも,次の助言が寄せられています.
組み込まれた図は,行の区切りに LF ではなく CR を使用しているため, これが問題の原因となる場合があります.これらを LF に変換して見ましょう.
tr '\015' '\012' < book.p2.ps > fixedbook.p2.psそして:
これは,リジナルの投稿者の問題ではありませんが, 出力紙に A4 を使っ ている国で, Dataproducts LZR1260E の様なプリンタを使用している場合, 印字用紙サイズが縦方向に引き延ばされてしまうことがあります. これは,他の Framemaker で生成されたファイルでも発生します. 疑いもなく PS インタプリタのバグでしょう. 修正には,A4 用紙の大きさを編集してやります. 以下のシェルスクリプトは,これらの問題を両方とも修正します.
#!/bin/sh cat $1 | tr '\015' '\012' | sed '/FMDOCUMENT$/s/612 792/595 842/'
→目次へ
tclVar.c は,IRIX C 4.0.1 では,変数に関するバグのため, 引数 -O0 でコンパイルされねばなりません.
Makefile のルール指定を以下のように書き換えてやります.
> # GGR SG needs -O0 for varargs at 4.0.1
>
> CC_SWITCHES0 = -O0 -I. -I${SRC_DIR} ${AC_FLAGS} ${MATH_FLAGS} \
> ${GENERIC_FLAGS} ${PROTO_FLAGS} ${MEM_DEBUG_FLAGS} \
> -DTCL_LIBRARY=\"${TCL_LIBRARY}\"
>
> tclVar.o: tclVar.c
> $(CC) -c $(CC_SWITCHES0) $<
Peter NEELIN (neelin@pet.mni.mcgill.ca) は,
次のような注意をしてます.
私は,ファイル Config.mk を次のように変更して, TclX 7.3a を SGI (irix4.0.5) でコンパイルしました.
71c71 < CFLAGS=-cckr -D__GNU_LIBRARY__ --- > #CFLAGS= 106,107c106,107 < TCL_PLUS_BUILD=TCL_PLUS < CCPLUS=g++ --- > #TCL_PLUS_BUILD=TCL_PLUS > CCPLUS=CC 191,193c191 < MAN_DIR_SEPARATOR= < < LIBOBJS=strftime.o --- > #MAN_DIR_SEPARATOR=.
-D__GNU_LIBRARY が,srandom 問題を解決しますが, 思うに,-cckr が waitpid でプロトタイプ・エラーを起こします (汚いですが,とりあえず動きます). strftime がなぜ必要だったかは,忘れてしまいました.
私の作成した Config.mk のバージョンが欲しいならば,メールして下さい.
→目次へ
TclX を blt_wish に追加する代わりに,別の方法でやってみましょう. BLTをwishxに追加するのです.これは,とっても簡単です.
ファイル ./tksrc/tkXAppInit.c の 116 行目に, 次のような BLT の初期化ルーチンを付け加えます.
if (TkX_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
if (Blt_Init(interp) != TCL_OK)) {
return TCL_ERROR;
}
そうしてやって,libBLT.a を wishx にリンクすれば,おしまいです.
他の手段として,tkmkmf や make-a-wish パッケージを使用してもいいでしょう.
→目次へ
Tcl と Tk 双方で,非 ANSI の Sequent cc ではなく,gcc を用います.
Tcl では,数学ライブラリに,2 つの問題があります. 第1に,Sequent の数学ライブラリが,'fmod' 関数を含んでいないことです. 私は fmod のソースを ftp.uu.net から入手し, サブディレクトリ compat に入れました. そして,それを Makefile に追加しました. fmod は,'isnan' と 'finite'関数を内部で使用していますが, tcl が無限と nan をサポートすると信じなかったので, それらはコメントアウトしただけです.
数学ライブラリのもう 1 つの問題は, そのライブラリ中に 'tanh' 関数のコピーが 2 つ, 含まれてしまっていることです."ar" を使って ライブラリをオブジェクトに分解し,再度組み立て直して, tanh のコピーを取り去ってしまえば,簡単に fix できます.
この様な変更を行えば,Tcl のコンパイルはきれいに終了し, 試験も,scanの試験以外はすべて通ります. どうも,Dynix では,*scanf 関数が壊れてる様です. この問題は,8 進数の終りで確認できます. 私は,ちょうど,この問題に取り掛かったところです. 解決策は,*scanf 関数のソースを見付けだし,それを使うことになるでしょう.
Tk をコンパイルするために, 私は wchar_t のようなものを定義した, 新しいバージョンの stddef.h を作らねばなりませんでした. 私はそれを別のインクルード・ディレクトリにコピーし, そのディレクトリを最初に指定して,それが参照されるようにしました. Tk でも数学ライブラリの問題 (tanh) が発生します. これら以外もありますが,すべてのコンパイルはきれいに終了し, すべての試験にもパスします.
→目次へ
$ /projects/xopsrc/wishx3.6a
Error: invalid command name "tk_bindForTraversal"
invalid command name "tk_bindForTraversal"
while executing
"tk_bindForTraversal Entry"
(file "/projects/xopsrc/Tclsrc/v7/lib/3.6a/tk.tcl" line 98)
invoked from within
"source $tk_library/tk.tcl"
invoked from within
"if [file exists $tk_library/tk.tcl] {
source $tk_library/tk.tcl
} else {
set msg "can't find $tk_library/tk.tcl; perhaps you "
append ..."
この様なケースでの *本当*の問題は,
正しく config されてないか,きちんとインストールされてないかのどちらかです.
コマンド名が本当は正しいならば,
外部変数が指しているディレクトリが,
デフォルトのそれを上書きしてしまっているか,
インストール時に指定してないかで,auto_pathが正しく設定されていないのでしょう.
→目次へ
→目次へ
→目次へ
#! wish -fその上,多くの Unix システムでは, #! 行に書ける文字列長の最大長さに制限があります. もし制限を越えてしまうと,期待通りの動作はしないでしょう. ですからwish のコードでは,次のようにしてもいけません.
#! /長いプロジェクト名/何か/長〜い/パス名/bin/sun4/wish -f行は短めにしておきましょう.32 文字以下を推奨します. kennykb@carla.crd.ge.com (Kevin B. Kenny)は, スクリプトの始めの行を以下のようにする技を推奨しています:
#!/bin/sh
# This line makes the next one a comment in Tcl \
exec /path/to/wish "$0" ${1+"$@"}
→目次へ
別の選択しとして,使用しているサーバに,スタティク・カラーのような, 別のビジュアル/カラーモデルが使えないか調べて見る手があります. この様なモデルの 1 つは,Tk をよりよく動かす事が出来るでしょう.
この情報を提供してくれた Nathaniel Borenstein (nsb@thumper.bellcore.com)に感謝します.
→目次へ
次に示す 2 つの汎用プロシージャを,ライブラリに置きます.
# envVal envValName
# 環境変数 envValName を見付けだし,その値を返す.存在しない場合は
# {} を返す.
proc envVal {envValName} {
global env
if [info exists env($envValName)] {return $env($envValName)} {return {}}
}
# loadAppDefaults classNameList ?priority?
# 指定したクラス名 className に一致する app-defaults ファイルを
# X ツールキット・イントリンシクス に指定された順番で探しだし,指定
# されたプライオリティ (デフォルトは startupFile) でロードする.
proc loadAppDefaults {classNameList {priority startupFile}} {
set filepath "[split [envVal XUSERFILESEARCHPATH] :] \
[envVal XAPPLRESDIR] \
[split [envVal XFILESEARCHPATH] :] \
/usr/lib/X11"
foreach i $classNameList {
foreach j $filepath {
if {[file exists $j/$i]} {
option readfile $j/$i $priority; break
}
}
}
}
そうしたならば,例えば,次のように xwf のコード中に記述します.
option add Tk.BoldFont "*-lucida sans-Bold-R-Normal-*-100-*" widgetDefault
loadAppDefaults {xwf XWF} userDefault
これは,プログラムのデフォルトをまず設定しています.
そして,ユーザのデフォルトのリソース値に指定されたデフォルト値を読み込み,
最後に,サイト毎,あるいは,一般的な app-defaults リソースを読み込みます.
勿論,
実行時にユーザがこれらの値を設定しなおすことが出来るようなプログラムを,
xwf に組み込んでやる事も可能でしょう.
Chris Milam (アドレス不詳) は, 様々な設定元からの app-defaults ファイルをマージする X11R5 の機構をサポートするよう変更した loadAppDefaultsを提供してくれました.
# loadAppDefaults classNameList ?priority?
# Searches for the app-default files corresponding to classNames in
# the order specified by X Toolkit Intrinsics (R5), and loads them with
# the priority specified (default: startupFile).
proc loadAppDefaults {classNameList {priority startupFile}} {
set lang [envVal LANG]
if {[string length $lang] > 0} { set lang /$lang }
set filepath "\
/usr/lib/X11${lang}/app-defaults \
[split [envVal XFILESEARCHPATH] :] \
[envVal XAPPLRESDIR]${lang} \
[split [envVal XUSERFILESEARCHPATH] :] \
"
foreach i $classNameList {
foreach j $filepath {
if {[file exists $j/$i]} {
option readfile $j/$i $priority;
}
}
}
}
→目次へ
→目次へ
→目次へ
→目次へ
Tk 3.3 では,X11 の xauth セキュリティ機構が使われています.
これは,より安全な環境を提供してくれますが,
ユーザに,通常よりは多い設定を要求します.
ユーザは,Xauthority ファイル(通常は $HOME/.Xauthority)を生成しなければならず,
また,X サーバを -auth オプションに,
生成した Xauthority ファイルのファイル名を付けて起動する必要があります.
xauth や,相当するソフトウェアの使い方,設定ファイルの記述法に関する詳細は,
使用しているシステムの X11 ドキュメントを参照して下さい.
xauth の入門の文章は,以下から入手可能です.
ftp://ftp.aud.alcatel.com/tcl/docs/Xauthority
ファイル tk3.3/Makefile.in を,以下のようにコメントアウトすることで, Tk を xauth によらず,動作させる事も可能です.
# To turn off the security checks that disallow incoming sends when # the X server appears to be insecure, reverse the comments on the # following lines: #SECURITY_FLAGS = SECURITY_FLAGS = -DTK_NO_SECURITY
→目次へ
このプログラムは,既に Tcl や Tk ライブラリ, ヘッダファイルなどがインストール済であることを前提としています.
→目次へ
bind Listbox <3> {%W select from [%W nearest %y]}
bind Listbox <B3-Motion> {%W select to [%W nearest %y]}
→目次へ
bind Entry <Delete> {}
→目次へ
keysym が,Tk にとって,その使用法が知られていないものであった場合, ファイル ks_names.h を修正する事で,対応させることもできます. この対応法で注意しなければならないことは, 他人は同様の修正をしているわけではない,という点です. しかしながら,これが新しい keysym を受け入れさせる唯一の方法です.
この注釈を寄せてくれた Wayne Christopher (faustus@CS.Berkeley.EDU) に感謝します.
→目次へ
この非常に貴重な情報を寄せてくれた Brad Morrison (brad@NeoSoft.com)に感謝します.
→目次へ
どんなキー入力に対しても,ウィンドウのタイトルバーを更新するように,
テキスト・ウィジェットをバインドしようとして,次のように書いて見ました.
text .textWin ...
bind .textWin <Any-KeyPress> {+wm title . "Nextedit - edited"}
これは,ウィンドウの中のテキストが編集済であるかどうかを, ユーザに知らせる機能をサポートします. 問題は "+" です.これは,どこに行くんでしょう? 色々な書き方を試して見ましたが,パーズ・エラーに終るか, wm コマンドが完全にバインドを乗っ取ってしまい, テキストに何の入力もできなくなるかになってしまいます. キー入力をテキストに入力させ, *かつ*タイトルバーを更新させるには, 別のバインドを付け加える必要があると思うのですが,どうすればよいのでしょう?Gerald W. Lester (gwl@cpu.com)が,答えました:
クラス指定のバインドを,ウィジェット指定のバインドに降ろす必要があります.
こうしてみて下さい.
bind .textWin <Any-KeyPress> Text
bind .textWin <Any-KeyPress> {+wm title . "Nextedit - edited"}
→目次へ
ConnectionNumber(Tk_Display(tk_window));を使って,Tk の接続ナンバを得て, XtAddInput を使ってこれを Xt のイベントハンドラとして記憶させることです. XtAddInput のコールバック関数は, Tk_OneEvent(1) を実行するプロシージャをラップします. Xt に記憶されていない Tk のファイルを読み込むことは,問題となるかも知れません.
この情報を寄せてくれたJoe Wang (joe@astro.as.utexas.edu)に 感謝します.
→目次へ
利用可能なカーソル名の一覧を調べるために, /usr/include/X11/cursorfont.h を参照します. カーソル名は,この中の記述から,頭の 'XC_' を取り去ったものです.
以下に示すのは,私のアプリケーションで, 何か動作中にカーソルの形状を変える 'busy' プロシージャです. 実行したいコマンドを引数にこれを呼ぶだけで,コマンドの実行が完了するまで, カーソルを時計マークに変更してくれます. (これを実行した後に生成される) 新しいウィンドウの中では, カーソルは通常の形状となる点は注意して下さい.
proc busy {cmds} {
global errorInfo
set busy {.app .root}
set list [winfo children .]
while {$list != ""} {
set next {}
foreach w $list {
set class [winfo class $w]
set cursor [lindex [$w config -cursor] 4]
if {[winfo toplevel $w] == $w || $cursor != ""} {
lappend busy [list $w $cursor]
}
set next [concat $next [winfo children $w]]
}
set list $next
}
foreach w $busy {
catch {[lindex $w 0] config -cursor watch}
}
update idletasks
set error [catch {uplevel eval [list $cmds]} result]
set ei $errorInfo
foreach w $busy {
catch {[lindex $w 0] config -cursor [lindex $w 1]}
}
if $error {
error $result $ei
} else {
return $result
}
}
→目次へ
→目次へ
→目次へ
Tk で,トップレベルウィンドウを生成し, それをマップせずに (wm withdraw) おきます. そうしておいて,他のウィンドウのサブウィンドウになるように, そのウィンドウの親を付け変えてからマップしてやります. Tk アプリケーションが別プロセスであったとき,これを行って見ました. でも,同じプロセスであったならば,各々のツールキットが制御を獲得しようとして, イベントループで問題が起きるでしょう.
→目次へ
<Enter> と <leave> イベントは, "%d" を使ってアクセス出来る,「詳細」フィールドを持っています. そのフィールドが "NotifyInferior" であるならば, マウスポインタが子ウィンドウを出入りすることを意味します (実際,イベントを受け取るウィンドウの領域に留まります). スクリプトの中で詳細フィールドをチェックできるようにすべきで, 値が NotifyInferior ならばイベントを無視してやります. 詳細フィールドの完全な情報と Enter/Leave イベントについては, Xlib のドキュメントを参照して下さい.
→目次へ
Tk と Xt のウィンドウの間で直接インタラクションする
(例えば,Xt でディスパッチされたルーチンで Tk のウィンドウを描画するとか)
様なものではありませんが,
両者がとりあえず動作する,重たいイベントループのルーチンを
(今まで) 書いてました.
XEvent xevent;
for (;;)
{
if (XtAppPending(appcontext))
{
XtAppNextEvent(appcontext,&xevent);
XtDispatchEvent(&xevent);
}
Tk_DoOneEvent(TK_DONT_WAIT);
}
[David C Mudie (mudie@radon.eecs.berkeley.edu) によれば]
私達は,後に示すメインのイベントループを使っています. 基本的なアイディアは,Xt のサーバ・コネクションと Tk のサーバコネクション両方から来るイベントを監視し, (イベントが来たならば) ライブラリのディスパッチャを呼ぶと言うものです.
次に示すコードの断片は,使用に当たっては,
きちんと書き直してやる必要があります.
インクルードファイルの指定や,グローバル変数の宣言は欠けています.
/* Allow Tcl/Tk and Xt to work at the same time. */
void tkGo(void)
{
extern Widget topLevel;
int width = ulimit(4, -1);
fd_set readfds;
struct timeval timeout;
int nfds;
int tkfd = ConnectionNumber(Tk_Display(mainWindow));
int xtfd = ConnectionNumber(XtDisplay(topLevel));
Tcl_VarEval(interp, "update", NULL);
while (1) {
/* Select on X server connections to wait for event. */
/* Timeout every half second to allow processing of non-X events */
FD_ZERO(&readfds);
FD_SET(tkfd, &readfds);
FD_SET(xtfd, &readfds);
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
nfds = select(width, &readfds, NULL, NULL, &timeout);
if (nfds < 0 && errno != EINTR) {
perror("select");
} else if (nfds == 0) {
/* printf("timeout\n"); */
}
while (XtPending()) {
XtProcessEvent(XtIMAll);
}
while (Tk_DoOneEvent(1)) {
/* do nothing */
}
if (mainWindow == NULL) {
// Tcl_DeleteInterp(interp);
// Tcl_DStringFree(&command);
Tcl_Eval(interp, "exit");
return;
}
}
}
[Davide Frisoni (frisoni@faw.uni-ulm.de) によれば]
異なったアプリケーション間の通信に, Xt のプロパティを用いることも出来るでしょう.
→目次へ
: bind .frame <ResizeRequest> {puts stdout "resise\n"}
: で,.frame がリサイズできず,標準出力に "resize" も出力されない,
: という問題を抱えてしまってるのですが.
以下のやりかた
bind .frame <Configure> {puts...}
を,試して下さい.動くはずです.
→目次へ
*geometry: +0+0
または,
Tk*geometry: +0+0
Tk はこの形式を好みません.ですから,これらの指定を削除するか, 次のような形式で完全に指定する必要があります.
widthxheight{+-}xoffset{+-}yoffset
実例を示すなら,
Tk*geometry: 200x200+0+0
→目次へ
"send"コマンドを削除してしまいましょう.こうすれば,インタプリタ名を X11プロパティから移動し(他のwishから,"winfo interps"で見れなくする), 他からの"send"処理を受け付けなくなります.sendコマンドの削除は, 次のようにして行えます.
rename send ""
→目次へ
> wishで以下のように実行すると,ウィンドウが約20ピクセル下に移動しました. > %wm geometry . [winfo geometry .] > なぜなのでしょう?
"wm geometry"はウィンドウマネージャが考えているジオメトリを返します. (一方,)"winfo geometry"は,Tkの考えてる値を返します.
このために,"wm geometry"がトップレベル・ウィジェットでしか 動作しないのに対して,"winfo geometry"は,全てのウィジェットで動作するのです. そして,これら双方をトップレベル・ウィジェットに対して使用した場合, "winfo"と異り"wm"は,タイトルバーの領域(この場合は約20ピクセル)も含めて 答えます.
→目次へ
#!/usr/local/bin/wish -f
wm minsize . 20 20
wm maxsize . 1152 900
pack append . [listbox .l -borderwidth 2 -relief raised] {expand fill}
テキストウィジェットで,きちんとサイズ変更を管理するにも,
同じ方法が用いられます.
John C Ellson (ellson@ontap.att.com) に感謝.
→目次へ
→目次へ
Tk の,この仕様を変更するには,リストボックスを生成する時に, -exportselection false を指定してやります. あるいは,コマンド
option add *Listbox.exportselection falseを,スクリプトの最初に書いてやります.
この話題を提供してくれた David Herron (david@davids.mmdf.com) に感謝.
→目次へ
listbox .l -geom 1x1 -setgrid 1 -yscrollcommand ".s set" -relief sunken -bd 2 scrollbar .s -command ".l yview" pack .s -side right -fill y pack .l -side top -fill both -expand 1 .l insert end one two three four five six seven eight nine ten "THE END"リストボックスに,表示仕切れないアイテムが存在する場合には, 底辺に半行のすき間が出来てしまいます. これは,ユーザがそこに何が表示されているのかと混乱させる元になってしまいます. なんで,こうなるのでしょう?
以下が,その答えです.
リサイズの前の,ウィンドウが生成されるところを見て見ましょう. 小さなかわいらしいスクロールバーが, 押し縮まって極小のウィンドウに表示されるのがわかるでしょう. これもまた,最小サイズを要求し,そうしてから, リストボックスのジオメトリの指定の, 開始で底辺までの利用できる空間が受け取られます. その結果,リサイズが文字単位に制約されるまでは,無くなりません.
やることは,実際に表示される行と列数で, ウィジェットの -setgrid 指定を行うことです. 上の例では,-geom 1x2 に設定すると,うまく誤魔化せます.
この情報を提供してくれた Frank Stajano (fms@cam-orl.co.uk)に感謝.
→目次へ
scrollbar .scroll -command {.scrollable_widget yview}
または,
scrollbar .scroll -command {.scrollable_widget xview}
このコマンドが実行される前に, (指定の内容に対して)空白文字と数値が付加されます. 数値は,スクロール可能ウィジェットが それ自身の位置をどれだけ動かせばよいかを指定する, 論理的な位置インデックスです. 従って,1個のスクロールバーで2つ(またはそれ以上)のウィジェットを制御するには, 単純にスクロールコマンドとしてプロシージャを用い, そのプロシージャで望む通りに複数のウィジェットをスクロールさせてやります. そのプロシージャは,1個の引数(すなわち,論理位置インデックス)を取るでしょう. 例えば,
proc ScrollCommand {index} {
.lb1 yview $index
.lb2 yview $index
.lb3 yview $index
}
scrollbar .scroll -command ScrollCommand
listbox .lb1 -geometry 4x5 -yscrollcommand {.scroll set}
listbox .lb2 -geometry 4x5 -yscrollcommand {.scroll set}
listbox .lb3 -geometry 4x5 -yscrollcommand {.scroll set}
pack .scroll .lb1 .lb2 .lb3 -side left -fill y
.lb1 insert 0 a b c d e f g h i j
.lb2 insert 0 0 1 2 3 4 5 6 7 8 9
.lb3 insert 0 A B C D E F G H I J
→目次へ
listbox .l tk_listboxSingleSelect .lこうすると, .lのバインディングは同時に1アイテムしか選択できないように変更されます.
.l configure -selectmode single
→目次へ
→目次へ
Jesper Blommaskog (d9jesper@dtek.chalmers.se).
→目次へ
< 論理的に埋め尽くすように描画されたオブジェクトのあるキャンバス (謂わ < ば,チェス盤や,世界地図みたいなものです) のあるウィンドウを作りまし < た.このトップレベルウィンドウをリサイズ可能にしたいのですが,勿論, < リサイズした時にはキャンバス内のオブジェクトを,リサイズされた大きさ < に従って大きさを変更させてやりたいのです.今のところ,オブジェクトの < サイズ変更自体はできますが,その処理をいつ起動するかのタイミングを検 < 出することが出来ずに困っています.ウィンドウがリサイズされた時のノー < ティファイは,どの様に得ればよいのでしょうか?Nat の答えは:
コマンドを Configure イベントにバインドする必要があります. 例えば,次のように,すればよいでしょう.
proc config {w h} {
puts stdout ".canvas - width = $w, height = $h"
}
bind .canvas <Configure> "config %w %h"
.canvas - width = 224, height = 251
.canvas - width = 224, height = 151
.canvas - width = 224, height = 243
# and so forth
→目次へ
スクロールコマンドのハンドラを書き換えてやる必要があります.
`scrollbar' コマンド (と,`listbox' コマンドも) のマン・ページを,
まず読みましょう.
すると,scrollbar コマンドで実行される様に,
次のようにその scrollcommand に追加すればよいことが分かるでしょう.
.f.c yview; .f.lb yview <offset>
最後に,私の最終的なものを付け加えておきます.
このコードは,スクロールが「右にならえ」である点が優れています.
listbox .l1 -relief sunken -yscrollcommand {
scrollMultiple_y { .l1 .l2 .l3 } .vs
}
listbox .l2 -relief sunken -yscrollcommand {
scrollMultiple_y { .l1 .l2 .l3 } .vs
}
listbox .l3 -relief sunken -yscrollcommand {
scrollMultiple_y { .l1 .l2 .l3 } .vs
}
scrollbar .vs -relief sunken -orient vertical \
-command {setMultiple_y {.l1 .l2 .l3}}
bind .l1 <1> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
bind .l1 <B1-Motion> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
bind .l1 <Shift-1> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
bind .l1 <Shift-B1-Motion> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
bind .l2 <1> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
bind .l2 <B1-Motion> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
bind .l2 <Shift-1> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
bind .l2 <Shift-B1-Motion> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
bind .l3 <1> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
bind .l3 <B1-Motion> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
bind .l3 <Shift-1> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
bind .l3 <Shift-B1-Motion> {
selectMultiple {.l1 .l2 .l3} [%W nearest %y]
}
proc scrollMultiple_y {lists vs total window first last} {
if {[expr $first+$window] < $total} {
set first [expr $total-$window]
set last [expr $first+$window]
}
setMultiple_y $lists $first
$vs set $total $window $first $last
}
proc setMultiple_y {lists index} {
foreach l $lists { $l yview $index }
}
proc selectMultiple {lists index} {
foreach l $lists { $l select from $index }
}
→目次へ
これは本当は(Tkレベルではなく)Tclに関する問題なのです. ですが非常によく聞かれる質問ですので解説してみましょう.
キャンバス・アイテムの全ては,生成時にその初期位置や形状を定義した,
2つかそれ以上の座標情報を必要とします.
これらの値をそれぞれ別々の変数に格納していたり,定数を使っているならば,
キャンバスのアイテムの生成は単純なものです.例えば:
.myCanvas create rectangle $x1 $y1 $x2 $y2 -fill blue
.myCanvas create text 100 250 -text "Hello, world"
ですが,多くの場合には,座標値は個々の変数に格納されてたりはいないものです. それらは,ファイルから読み込んだり,何らかの計算ルーチンからの返値であったり, 他の座標情報のリストから取り出したりした,一つの変数に格納されたリストの 形をとるでしょう.この場合,キャンバスコマンドが実行される前に, 座標情報のリストを分解してやらねばなりません. これには,`eval'コマンドを使ってやります. 以下に幾つかの例題を示しましょう.
canvas .myCanvas
pack .myCanvas
#
# 例題 1
#
# 与えられた2座標情報のリストでテキスト・アイテムを生成.
#
set coords {150 50}
eval .myCanvas create text $coords -text hello
#
# 例題 2
#
# 以下に示すプロシージャは,与えられた点を中心点に,指定された
# 高さと幅の4角形の座標情報を返す.以下の例題で用いる.
#
proc CenteredRectangle {centerX centerY width height} {
return [list [expr $centerX - $width / 2.0] \
[expr $centerY - $height / 2.0] \
[expr $centerX + $width / 2.0] \
[expr $centerY + $height / 2.0]]
}
eval .myCanvas create rectangle [CenteredRectangle 80 5 10 75]
eval .myCanvas create rectangle [CenteredRectangle 5 80 75 10]
eval .myCanvas create oval [CenteredRectangle 140 110 75 50]
#
# 例題 3
#
# 以下のルーチンは,指定された点を中心点に,四角形で囲まれたテキスト
# アイテムを生成する.
#
proc CenteredBoxLabel {w centerX centerY text} {
set id [$w create text $centerX $centerY \
-text $text \
-anchor center]
eval $w create rectangle [$w bbox $id]
}
CenteredBoxLabel .myCanvas 33 42 "Hello, world"
#
# 例題 4
#
# サイン波形を描画
#
set coordList {}
loop x 0 314 {
lappend coordList $x [expr sin($x/25.0) * 50 + 100]
}
eval .myCanvas create line $coordList
set coordList {}
for {set x 0} {$x < 314} {incr x} {
lappend coordList $x [expr sin($x/25.0) * 50 + 100]
}
eval .myCanvas create line $coordList
例えば {{25 10} {30 12} {35 14}} の様な座標情報の組のリストを使いたい場合には, 平坦なリスト構造に直してやるというステップが必要になります. 以下の例を試してみましょう:
#
# 例題 5
#
# 2要素リストのリストから始めます ...
#
set coordPairs {{25 10} {30 12} {35 14}}
#
# ... (前述の例題のように)ただの数字のリストの形式に平坦化.
#
set flatList [eval concat $coordPairs]
#
# 後は,これまでの例題と全く同じ.
#
eval .myCanvas create line $flatList
まとめましょう. eval,concat,listコマンドのドキュメントを注意深く読めば, 座標情報と`canvas create'コマンドを 実行可能な正しいTclコマンド形式にまとめあげることが出来るようになります.
→目次へ
→目次へ
text .t -width 20 -height 20 -relief sunken -borderwidth 4
→目次へ
そして,次に示すコードは,Michael Moore (mdm@stegosaur.cis.ohio-state.edu)から寄せられた, Tkのみでこれを行う方法です.
#! /bin/wish -f
#
# This demonstrates how to create a scrollable canvas with multiple
# buttons.
#
# Author : Michael Moore
# Date : November 17, 1992
#
#
# This procedure obtains all the items with the tag "active"
# and prints out their ids.
proc multi_action {} {
set list [.frame.canvas find withtag "active"]
puts stdout "Active Item Ids : "
foreach item $list {
puts stdout $item
}
}
#
# This simulates the toggling of a command button...
# Note that it only works on a color display as is right now
# but the principle is the same for b&w screens.
#
proc multi_activate {num id} {
set tags [.frame.canvas gettags $id]
if {[lsearch $tags "active"] != -1} {
.frame.canvas dtag $id "active"
.frame.canvas.button$num configure \
-background "#060" \
-activebackground "#080"
} else {
.frame.canvas addtag "active" withtag $id
.frame.canvas.button$num configure \
-background "#600" \
-activebackground "#800"
}
}
proc setup {} {
frame .frame
scrollbar .frame.scroll \
-command ".frame.canvas yview" \
-relief raised
canvas .frame.canvas \
-yscroll ".frame.scroll set" \
-scrollregion {0 0 0 650} \
-relief raised \
-confine false \
-scrollincrement 25
pack append .frame \
.frame.scroll {left frame center filly} \
.frame.canvas {left frame center fillx filly}
pack append .\
.frame {left frame center fillx filly}
button .frame.canvas.action \
-relief raised \
-text "Action" \
-command "multi_action"
.frame.canvas create window 1 25 \
-anchor w \
-window .frame.canvas.action
for {set i 2} {$i > 26} {incr i} {
button .frame.canvas.button$i \
-relief raised \
-background "#060" \
-foreground wheat \
-activebackground "#080" \
-activeforeground wheat \
-text "Button $i"
set id [.frame.canvas create window 1 [expr $i*25] \
-anchor w \
-window .frame.canvas.button$i]
.frame.canvas.button$i configure \
-command "multi_activate $i $id"
}
}
setup
→目次へ
wm minsize . 0 0
text .text
pack append . .text {fill expand}
→目次へ
→目次へ
記事 <1993Jun23.065417.4302@ericsson.se>で, 私の書いたことによると:
|> 私は現在,もう 1 つの tn3270 端末を開発してるのですが,同じサイズの |> ボタンを生成するところで躓いてます.PF とカーソルキーのためにボタン |> の配列を生成したのですが,それらを,みんな同じ大きさにしたいのです. |> それらを一列に配置する事は問題ではありませんでした.が,それらにビッ |> トマップを表示させると,水平位置がずれてしまうのです.ボタンの,水 |> 平・垂直サイズを winfo で読み取り,それらの最大サイズにあわせてサイ |> ズを統一するよう pad を入れたのですが,どうもうまく動きません. |> ビットマップとテキストを混用して,テキストボタンでピクセル単位にサ |> イズ指定するのに,水平・垂直サイズをプリセットする技はうまくない様 |> です.どなたか助言頂けませんか?
Jim Wight (J.K.Wight@newcastle.ac.uk) は, reqheight と reqwidth を用い, 各ボタンの pack コマンドで padx と pady を指定する事を助言しました. Jim の言うには:
私がこのグループに投稿した, 最初の回答の試みに欠けてるものを補うにはどうしたらいいかという記事に対して, reqwidth と reqheight を使うようにと答えてくれた Tuomas Tuomas J Lukka (lukka@klaava.Helsinki.FI)の回答が いいと思います.
余計な話は抜きにして, 私が Michael にメールした,最終版の解決法を,以下に示します.
frame .frame1
frame .frame2
button .frame1.a -text "pretty long button text"
button .frame1.b -text "short one"
button .frame2.c -bitmap "@/usr/include/X11/bitmaps/xlogo32"
button .frame2.d -text "tiny"
set long [winfo reqwidth .frame1.a]
set short [winfo reqwidth .frame1.b]
set medium [winfo reqwidth .frame2.c]
set tiny [winfo reqwidth .frame2.d]
set pady [expr [winfo reqheight .frame2.c]-[winfo reqheight .frame2.d]]
pack append .frame1 .frame1.a "filly pady $pady"
pack append .frame1 .frame1.b "fillx padx [expr $long-$short] filly pady $pady"pack append .frame2 .frame2.c "fillx padx [expr $long-$medium] filly"
pack append .frame2 .frame2.d "fillx padx [expr $long-$tiny] filly pady $pady"
pack append . .frame1 {left} .frame2 {left}
→目次へ
radiobutton .times -text Times -anchor w
radiobutton .helvetica -text Helvetica -anchor w
radiobutton .courier -text Courier -anchor w
pack .times .helvetica .courier -side top -fill x
pack コマンドにではなく,
ウィジェットそれ自信のオプションでanchorをwestに指定する点に注意して下さい.
こうすると,packer は幅一杯のボタンにしてくれます.
→目次へ
set default "foobar" entry .foo -width 25 -state disabled -textvariable default
→目次へ
Tk*activeBackground: #efefef
Tk*activeForeground: black
Tk*selector: black
Tk*background: #dfdfdf
Tk*foreground: black
Tk*selectBackground: #bfdfff
Tk*Scale.activeForeground: #efefef
Tk*Scale.sliderForeground: #dfdfdf
Tk*Scrollbar.foreground: #dfdfdf
Tk*Scrollbar.activeForeground: #efefef
Tk*Button.disabledForeground: #7f7f7f
Tk*Checkbutton.disabledForeground: #7f7f7f
Tk*Radiobutton.disabledForeground: #7f7f7f
Tk*Menu.disabledForeground: #7f7f7f
より詳細な情報は,
使用しているシステムのXリソースの読み込みに関するドキュメントや,
Tkのマニュアル・ページの"e;option"e;の項を参照して下さい.
→目次へ
button .w1 -text button; # .w1 を生成
frame .w2; # .w2 を生成
pack .w1 -in .w2; # .w1 を .w2 の内側にpack
pack .w2; # .w2 をメインウィンドウにpack
# buttonは,何処にいったの?
回答:短く言ってしまうと,"e;raise .w1"e;. 例題では,.w1は正しく.w2の内側に置かれていますし, 互いの大きさによる.w1と.w2とのサイズ調整も正しく動作しています. ただ,.w1は.w2の「裏側」にいるのです. なぜなら,デフォルトでは, ウィンドウは生成された順番でスタック方式に記憶されるからです. スタック内のウィンドウの順番は, 明示的に"e;raise"e;コマンドを実行することで変更でき, この場合では,"e;raise .w1"e;がそれにあたります.
→目次へ
アプリケーション中の各ウィンドウを破壊するには,`destroy'コマンドを使います. 以前の版のTkでは,destroyは1引数しか受け付けませんでした. が,現在は可変引数個の破壊すべきウィンドウ名(のリスト)を受け付けます. したがって,求めることを行うには,以下のようにしてやります:
eval destroy [winfo children .]
子ウィンドウ名は,可変個の空白で区切られたリスト形式で返され得ますので, evalコマンドが必要です.こうすれば,destroyに長い文字列としてではなく, 個々のウィンドウ名として渡されます.
→目次へ
ラジオボタンをグループ化するには,同じグループに属させたいボタン全てに, 同じ変数名の変数を割り振ればよいのです.(ラジオボタンの)デフォルトの 変数名はselectedButtonですので,-variable指定を行わなければ,全ての ラジオボタンは同じグループとなります.
例題: radiobutton .left.button1 -text "Left button 1" -variable leftChoice radiobutton .left.button2 -text "Left button 2" -variable leftChoice radiobutton .left.button3 -text "Left button 3" -variable leftChoice radiobutton .right.button1 -text "Right button 1" -variable rightChoice radiobutton .right.button2 -text "Right button 2" -variable rightChoice radiobutton .right.button3 -text "Right button 3" -variable rightChoice
→目次へ