Wish Tcl/Tk 入門

Wish Tcl/Tk 入門

5. サブルーチン proc

関数やサブルーチンの様に、同じ処理を何回もする場合には、 この手続きを proc でまとめるのが便利です。変数を受渡し 結果を返します。また単に手続きを分割して分かりやすくする利点 があります。

5.1 パスワード入力

(実行例 5.1) 良く使う手続きは、実行の前の身分証明として passwd を入力する例です。passwd の check を proc でします。
#!/bin/sh
# the next line restarts using wish \
exec wish "$0" "$@"
# passwd.tcl 5.1
#
# proc でも main でも共通する global 変数 を 宣言
# ok, login, passwd の 3 つの 変数です。
#
global ok login passwd
#
set ok "Tab:入力切替 CR:実行"
#
# ラベルを 4 つのフレームに分割して所属させ
#  pack の表示を意図した並び方にします。
#
frame .f0 
frame .f1
frame .f2
frame .f3 
#
# いろいろな label を作ります。
#
# パスワード の entry は -show * で * で 表示します。
#
label .f0.lb0 -text " Welcome to Localhost " -bg white -fg black
label .f1.lb1 -text ログイン名 -bg white -fg black
entry .f1.en1 -textvariable login -bg white -fg blue
label .f2.lb2 -text パスワード -bg white -fg black
entry .f2.en2 -textvariable passwd -bg white -fg blue -show *
label .f3.lb3 -textvariable ok -bg white 
#
# configure コマンドで .lb3 の -fg の属性を変えます。
#
.f3.lb3 configure -fg blue
#
pack .f0 .f1 .f2 .f3 -fill both -expand yes
pack .f0.lb0 -fill both -expand ye
pack  .f1.lb1 .f1.en1 -side left
pack  .f2.lb2 .f2.en2 -side left 
pack  .f3.lb3 -side left -fill both -expand yes
#
# focus で login への入力を促します。
#
focus .f1.en1
# 改行で login と passwd の比較がなされます。
#
# proc checkPW に 引数 $login と $passwd $ok を引き継ぎます。
# 
# entry .en1 での 改行はただ passwd field に行かせます。
# entry .en2 の改行と checkPW の呼出を結びます。
#
bind .f1.en1   { focus  .f2.en2 }
bind .f2.en2   { checkPW }
#
# 手続き checkPW を定義
#
proc checkPW { } {
#
# proc でも global 変数 ok login passwd が有効になるように宣言
#
global ok login passwd
#
    if { ( $login == "user" ) && ( $passwd == "pass" ) } {
        .f3.lb3 configure -fg blue 
	set ok "login は成功" }\
  else { 
        .f3.lb3 configure -fg red
        set ok "login 失敗" }
# いずれの場合にも login と passwd の中身を clear します。
# また 入力を login の 位置に持って行きます。
        set login ""
        set passwd ""
        focus .f1.en1
return
    }

login 名 user passwd pass で login 成功になります。

login が 失敗したときには、login 失敗は色を configure で 属性を その時点で変更しています。

passwd field で 改行キー をすると checkPW が よ ばれます。内容が proc checkPW に移ります。window の pathname (.fr2.en2 など) は proc でも 共通に使えます。変数は共通に使 えません。簡単に共通に使うようにするには global で変数を そ れぞれで 宣言します。同じ宣言があった proc では 変数がそのま ま代入することが有効です。

login のところで return を押しても普通は何も処理してくれ ません。ここで bind して passwd の入力窓に移る (focus) する ようにしました。login が成功しても、失敗しても もとの login の window に戻るようにしています。

この プログラムは分かりやすいように $passwd の比較は 生 の pass と直接比較しています。この passwd.tcl の ソースが見 える状況ではまったく意味がありません。実際に利用する場合には、 入力した passwd を暗号化し、また pass を 暗号化したものと比 べることが必要です。pass の暗号化したものが ソースで例え見ら れても、それが何を暗号化したものかを見極めるのは非常に大変で す。

5.2 単位変換電卓

(実行例 5.2) 5.1 の proc は、変数の引渡しは global 変数を用 いていました。ここでは、proc の引数として変数を受渡し、 return と 引数で変数を返します。こうしますと、proc は、独立 した処理として、他のプログラムに拡張しやすくなります。

単位変換は、わかってはいるけどめんどくさいものです。 電卓のように変換できたら便利ですね。それぞれの変換手段を proc にまとめました。


#!/bin/sh
# the next line restarts using wish \
exec wish "$0" "$@"
# tannihenkan.tcl  5.2
#
# 単位を変換するプログラムです。
#
label .lb1 -text 数値をいれてください。 -bg white
entry .en1 -textvariable value -width 20 -relief ridge -bg yellow
button .bt1 -text 実行 -command { set value [ $henkan $value ] }
#
# 改行でも実行するとします。
#
bind .en1  { set value [ $henkan $value ] }
#
# 変換操作はラジオボタンで択一選択します。
#
radiobutton .r1 -text "インチ -> cm" \
      -variable henkan -value intocm
radiobutton .r2 -text "cm -> インチ" \
      -variable henkan -value cmtoin
#
# pack で 表示させます。
#
pack .lb1 .en1 -anchor c 
pack .r1 .r2 -anchor w 
pack .bt1 -anchor c
#
# .r1 のボタンを押しておきます。
#
.r1 invoke
#
# インチ -> cm の変換 proc です。
#
proc intocm { in } {
set ch [ expr $in * 2.54 ]
return $ch
}
#
# cm -> インチ の変換 proc です。
#
proc cmtoin { cm } {
set in [ expr $cm / 2.54 ]
return $in
}

数値をいれて、変換したい方向のボタンを押します。 ラジオボタンは、押されたボタンの 1つしか on になりません。 3 つ以上ラジオボタンがあっても同じように動作します。 ラジオボタンが押されますと、henkan という 変数にどの proc を 呼ぶか proc 名が入ります。

実行ボタンまたは entry 1 で 改行が押された場合には、 henkan の名前の proc を value の値を引数にして送ります。 そして return で戻されたあたいを再び value の値にいれます。

{ set value [ $henkan $value ] }

の表現は良く使われますので覚えておいてください。

ここで注目したいのは、proc の中で使われている変数は、 メインのプログラムと同じ名前であっても同じ値が入るわけではあ りません。引数として受け継がれた変数 proc intocm なら 引数で ある in だけがメインのプログラムの value の値を引き継ぎます。 ですから in と value の名称が異なっても問題ありません。この 方が、この proc を他の目的で他の所に使う場合には大変便利です。

このように proc に 変数値を引き継ぐには global 変数の方 法と、引数として使う場合の 2 つがあります。同じ変数名で両方 同時に指定することはできません。(同時に指定する意味はないは ずです。) 別の変数なら、2 つの方法を別々に使っても問題があり ません。関数の値としては引数を、また両方で同じ意味で使う変数 は global 変数と分けて使うのが便利です。


rsaito@ee.uec.ac.jp