- TCl/Tkの利用法
教科書のp.141からTcl/Tkの説明がある。教科書では、EWIPEを利用してプレゼンテーションを行うことに特化した内容であるが、この言語は使い道がたくさんある便利なものなので少し実習してみる。詳しくは専門書を参考する必要があるが、今回はあらかじめ決められた手順のスクリプトを用いて、実際に Tcl/Tkを利用してプログラムを行うだけとする。それだけで雰囲気をつかむのは難しいが、TkというツールキットはTclだけではなく、Perlなどでも使用可能であり、また、WindowsやMacにも移植されているので幅広いプラットフォームでグラフィカルなアプリケーション作成が行えるので少しさわっておいても損はない。
まずは、Kterm 上で
$ wish
と入力する。すると、下に示すように、画面に小さな窓があらわれ、Kterm上のプロンプト(コマンド待ちの記号)が%に変わる。
ここでは、WIndow SHellというシェル(ユーザとOSの仲立ちをしてくれる環境であり、MacであればFinderの様なもの)を使って、GUI (Graphical User Interface) を利用しながらプログラミングを行なえるようになっている。ここでは、再びKtermに戻って作業を進める。まず、以下のような文字を%のプロンプトに続けて入力する。ただし、%はプロンプト記号を表しており、入力の必要は無い。
%button .b0 -text "Button" -command "exit"
ここでEnterとすると、.b0と表示され再びプロンプトが現れる。さらに、
%pack .b0
として、Enterを押す。さて、結果はと言うと、先ほど現れたウィンドウが小さくなり、下のようなButton と書かれたボタンが出現するはず。
マウスでそのウィンドウを選択し、ボタンをクリックするとウィンドウが消える。
大雑把に言うと、コマンドを打ち込んだのが Tcl という言語であり、ウィンドウが Tk というツールキットになっている。wishを実行すると、tclというシェルtclsh が起動し、ウィンドウが開く。%はtclshというシェルのプロンプトである。
通常のKtermでは以前から説明しているようにbashというシェルが動作しており、プロンプトは$マークである。
上で実行したプログラムはButton というテキストを持つボタンでそれを押した時に実行するコマンドはexitである、そういう図形をウィンドウ内にpackしなさい、という内容であった。毎回コマンドを入力しながら実行するのは効率が悪いので、次にスクリプトを書く方法を紹介する。
- スクリプトの作成
先ほどと同様の作業を行うために、XEmacsに移り以下のようなテキストを入力する。
#!/usr/bin/wish
button .b0 -text "Button" -command "exit"
pack .b0
次にこの内容をmybuttonという名前で保存する。その後、Ktermに戻り以下のコマンドを入力し、Enterキーを押す。
$ chmod +x mybutton
これにより実行可能なスクリプトファイルであることを宣言している。実際に実行するためには、Ktermにおいて、
$ ./mybutton
と入力する。さて、上手く動作しただろうか?
このように、あらかじめ用意されているGUIツールを並べて動作を指定することによりプログラムを作成するのが、Tcl/Tkである。本来ならば、ここで各種のツールに関して詳細な説明をしないと、実際に使用できるようなアプリケーションはできないが、時間の制約もあるので、内容はおいておき、各種のプログラムを書いて行く。興味があれば、自分で勉強するなどして欲しい。
- ○×ゲームの作成
以下に示す内容を、mygameと言う名前でXEmacs上で作成する。ファイルメニューから新規ファイルを選んでmygameと言う名前を付けてから入力を始める。また、このwebページから下にある○と×の絵をダウンロードして使っても良いし、自分でThe Gimpなどを使ってcircle.gifやcross.gifを作成してもよい。ダウンロードの方法は画像にマウスを当てて右クリックするとメニューが表示されるのでその中からSave Image As...を選択し、適当なファイル名を付けて保存する。以下のスクリプトでは、○の画像をcircle.gif、×の画像をcross.gifとしている。
circle.gifのデモ用画像 cross.gifのデモ用画像
#!/usr/bin/wish
. configure -width 256 -height 192
image create photo maru -file circle.gif
image create photo batu -file cross.gif
image create photo blank -width 64 -height 64
label .l0 -text "○か×\nを選択"
checkbutton .c0 -image maru -selectimage batu \
-indicatoron false -offvalue maru -onvalue batu -variable val
button .b9 -text "終了" -command "exit"
place .l0 -x 0 -rely 0.0 -relwidth 0.25 -relheight 0.333
place .c0 -x 0 -rely 0.333 -relwidth 0.25 -relheight 0.333
place .b9 -x 0 -rely 0.667 -relwidth 0.25 -relheight 0.333
for { set i 0 } { $i < 9 } { incr i } {
button .b$i -image blank -command ".b$i configure -image \$val"
place .b$i -x [expr 64*($i/3)+64] -y [expr 64*($i%3)]
}
入力が完了したら、先ほどと同様にKtermで
$ chmod +x mygame
とし、実行権限を与えた後、
$ ./mygame &
としてプログラムを起動しよう。
このゲームは下図のように○の絵と×の絵を使って○×ゲームを行うプログラムである。左の○をクリックすると×にかわり、逆も同様である。人間どうしが対戦する形式の冴えないプログラムであるが、この程度のことがたった16行で書けるのが便利であることが実感できただろうか。
さて、これ以降は時間の許す限りで良いので以下の入力を行うか、さらにその次の作業をするか自分で選んで欲しい。
- 少し高度なプログラム例
次のプログラムは簡単なテキストエディタとファイルマネージャである。簡単なプログラムで結構見栄えのよいものが作成できることを実感して欲しい。ここでも、ファイルマネージャに用いるアイコン画像はwebからダウンロードしても良いし、自分で作成してもよい。また、テキストエディタは、ちょっとしたファイルの修正などの作業に起動に時間がかかるXEmacsを利用するよりも手軽であるので利用価値がありそうである。
テキストエディタ
テキストエディタ起動コマンド
$ ./myedit &
もちろん、
$ ./myedit hoge.txt
のように直接ファイルを開くこともできる。また、エディタで日本語を入力する場合には、Ctrl + \によりCannaを起動する。Cannaを止めるときは、Shift + Spaceとする。
テキストエディタスクリプト
#!/usr/bin/wish
kanji defaultInputCode EUC
text .t0 -width 50 -height 20 -yscrollcommand ".s1 set"
scrollbar .s1 -orient vertical -command ".t0 yview"
frame .f0
menubutton .b0 -text "ファイル" -menu .b0.m0
menu .b0.m0
.b0.m0 add command -label "新規.." -command { .t0 delete 1.0 end}
.b0.m0 add command -label "開く.." -command {
.t0 delete 1.0 end
set F [open [tk_getOpenFile]]
while {[gets $F line]>=0} {.t0 insert end $line\n}
close $F
}
.b0.m0 add command -label "保存" -command {
toplevel .dialog
label .dialog.l0 -text "保存先"
entry .dialog.e0 -background white -textvariable Hozonsaki
button .dialog.b0 -text "OK" -command {
exec touch $Hozonsaki
set fileID [open $Hozonsaki w]
puts $fileID [.t0 get 1.0 end]
close $fileID
destroy .dialog
}
pack .dialog.l0 .dialog.e0 .dialog.b0
}
.b0.m0 add separator
.b0.m0 add command -label "終了" -command {exit}
pack .b0 -in .f0 -side left
grid .f0 -row 0 -column 0 -columnspan 2 -sticky ew
grid .t0 -row 2 -column 0 -sticky nsew
grid .s1 -row 2 -column 1 -sticky ns
grid rowconfigure . 2 -weight 100
grid columnconfigure . 0 -weight 100
ファイルマネージャ
以下に示すスクリプトにより起動するファイルマネージャ(Windowsにおけるエクスプローラーのようなもの)はまだマウスによるフォルダのオープンなどはできない。上部の窓にあるディレクトリに文字で入力してそのディレクトリ内のファイルを表示する。ここで、フォルダのアイコン (Folder.gif) で示されるのが、ディレクトリであり、鉛筆 (App.gif) は、実行プログラムを示す。最後に書類のアイコン (File.gif) は通常のファイルである。上の図とはアイコンの図柄が異なっているが、動作は同じである。
ディレクトリの概念を学習するのに利用できると思うので、時々使ってみてディレクトリ構造をWinやMacの階層フォルダに見立てて把握してみるのもいいかもしれない。
Folder.gif App.gif File.gif
ファイルマネージャ起動コマンド
$ ./myfm &
ファイルマネージャスクリプト
#!/usr/bin/wish
kanji defaultInputCode EUC
set Crtdir [exec pwd]
wm title . $Crtdir
image create photo File_Icon -file File.gif
image create photo App_Icon -file App.gif
image create photo Folder_Icon -file Folder.gif
proc GetInfo { } {
global Crtdir FilenameList IconNum Filename IconImage
set FilenameList [exec ls -F $Crtdir]
set IconNum [llength $FilenameList]
for { set i 0 } { $i < $IconNum } { set i [expr $i+1]} {
set Filename($i) [lindex $FilenameList $i]
image create photo IconImage($i)
if { [ string first "/" $Filename($i) ] > -1 } {
IconImage($i) copy Folder_Icon
} else { if { [ string first "*" $Filename($i) ] > -1 } {
IconImage($i) copy App_Icon
} else {
IconImage($i) copy File_Icon
}
}
}
}
proc SetIconXY { } {
global IconNum iconX iconY canvasY
for { set i 0} { $i < $IconNum } { set i [expr $i+1]} {
set iconX($i) [expr (100+15)*($i%4)+60]
set iconY($i) [expr 80*($i/4)+45]
}
catch {
set canvasY [expr $iconY([expr $IconNum-1])+70]
} { set canvasY 500}
}
proc BuildGUI { } {
global Crtdir canvasY
canvas .c0 -width 500 -height 500 -yscrollcommand ".s1 set" -bg white -scrollregion " 0 0 500 $canvasY "
scrollbar .s1 -orient vertical -command ".c0 yview"
frame .f0
entry .e0 -textvariable Crtdir
pack .e0 -in .f0 -fill x
grid .f0 -row 0 -column 0 -columnspan 2 -sticky ew
grid .c0 -row 2 -column 0 -sticky nsew
grid .s1 -row 2 -column 1 -sticky ns
}
proc DrawIcon { } {
global IconNum Filename IconImage iconX iconY
for { set i 0 } { $i < $IconNum } { set i [expr $i+1]} {
.c0 create image $iconX($i) $iconY($i) -image IconImage($i)
.c0 create text $iconX($i) [expr $iconY($i)+35] -text $Filename($i)
}
}
proc Refresh { } {
global canvasY
GetInfo
SetIconXY
.c0 delete all ; .c0 configure -scrollregion " 0 0 500 $canvasY"
DrawIcon
}
GetInfo
SetIconXY
BuildGUI
DrawIcon
bind .e0 <Return> {
Refresh
}
- 終わりに
以上で本日のTcl/Tkの作業を終わる。Linuxの真価が発揮できるような高度なプログラミングはきちんと言語を学習しないと行なえないが、実際に使えるものを自分でプログラムすることの楽しさのようなものが感じられたとしたら、今回の目的は達成されている。ネットワークやゲームの端末としてのコンピュータだけではせっかくの性能が勿体無い。自分で少しずつプログラミングを覚えて行くことにより、コンピュータの世界は大きく広がることを知っておいて欲しい。
- 謝辞と参考文献
本日のスクリプトの例は下記の文献から拝借しました。素晴らしい例題を作成してくれた方々に感謝します。
久野靖、「入門Tcl/Tk」アスキー出版局、1997.
宮脇大作、「Tcl/Tkで始める簡単GUIプログラミング」Linux Japan, August 1999, pp.126-135.
宮脇大作、「Tcl/Tkで始める簡単GUIプログラミング」Linux Japan, September 1999, pp.123-129.