目次

ボタンメソッド実装

 GUI上に配置した各ボタンオブジェクトは、専用の
 メソッド(仕事)をもたせて、システム全体での
 動作を確定します。

 次の順で、メソッドを記述していきました。


fload

 ファイルリストから、ユーザーにファイル名を指定  してもらい、該当ファイルから情報取得。取得情報  を連想配列に格納するのが仕事です。  動作シーケンスを書き出すと、以下。
  1. ファイルを指定してもらう
  2. ファイルオープン
  3. 6行に対して、1行ごとの情報を読取り、連想配列に格納
  4. ファイルクローズ
 コードにまとめます。 proc fload {} { # global tFileName xexe_temp xexe_time # set theFileName [tk_getOpenFile -filetypes {{"profile code file" {.txt}}}] # show file name set xtmp [split $theFileName /] set cFileName [lindex $xtmp end] set tFileName [lindex [split $cFileName .] 0] # open set fd_in [open $theFileName "r"] # read context set i 0 while { [gets $fd_in sbuf] >= 0 } { # separate hash item set iname [lindex $sbuf 0] set itemp [lindex $sbuf 1] set itime [lindex $sbuf end] # store set xexe_temp($iname) $itemp set xexe_time($iname) $itime # increment incr i } # close close $fd_in }  温度、時刻の連想配列は、グローバル変数xexe_tempと  xexe_timeに分けておきます。

fsave

 ファイル名をFileNameエントリーから取得し  該当ファイルを新規作成後、温度、時刻の2  情報を1行にまとめて保存します。  動作シーケンスを書き出すと、以下。
  1. ファイル名取得
  2. ファイルオープン
  3. 6行に対して、1行ごとに連想配列から情報をまとめて格納
  4. ファイルクローズ
 コードにまとめます。 proc fsave {} { # global tFileName xexe_temp xexe_time # if { $tFileName == "" } { tk_messageBox -message "not entry File Name" -type ok } else { # create file name set cFileName "$tFileName.txt" # open set fd_out [open $cFileName "w"] # store for {set i 0} {$i < 6} {incr i} { # get items set xfirst [format "P%1d" $i] set xsecond $xexe_temp($xfirst) set xthird $xexe_time($xfirst) # concatenate set xtmp "$xfirst $xsecond $xthird" # save puts $fd_out $xtmp } # close close $fd_out } }  ファイル名がない場合、ファイルを生成できないので  エラーメッセージを表示し、メソッドを終了します。

fexec

 ボタンのクリックで、1秒周期で温度、時刻を計算後  表示するのが主たる仕事です。  計算する前に、必要な情報が揃っていて時刻については  昇順に並んでいるかを確認します。時刻が昇順でないと  エラーとして動作を中断終了します。  時刻が昇順になっているかは、次のコードで確認します。 # judge set xp0 [calc_time $xexe_time(P0)] set xp1 [calc_time $xexe_time(P1)] set xp2 [calc_time $xexe_time(P2)] set xp3 [calc_time $xexe_time(P3)] set xp4 [calc_time $xexe_time(P4)] set xp5 [calc_time $xexe_time(P5)] set xflag 0 if { $xp0 > $xp1 } { incr xflag } if { $xp1 > $xp2 } { incr xflag } if { $xp2 > $xp3 } { incr xflag } if { $xp3 > $xp4 } { incr xflag } if { $xp4 > $xp5 } { incr xflag }  時刻を配列から取得して、隣接するステート間で  昇順になっているかを判定しています。  計数フラグ$flagを用意して、昇順でないとき  +1して増やしておきます。計数フラグの値が  0でないときには、時刻の並びが正しくないと  判断できます。  時刻の算出は、次の手続きで求めます。 proc calc_time {x} { # separate set stmp [split $x :] # calculate set result [expr [lindex $stmp 0] * 60 + [lindex $stmp end]] return $result }  文字列を「:」で2分割。  左右の文字列を数値として、重みを乗算し  オフセットを加算する方法を採用しました。  温度と時刻の1秒ごとの計算は、シフトレジスタを  利用して求めます。  リストxlistに、数値が次のように格納されているとします。 xlist = "xa xb xc xd xe xf"  隣合う数値の差分を求めるために、リストの先頭に0を追加  したリストをつくります。 ylist = "0 $xlist"  xlistの要素数分だけ差分を求めて、リストに格納。 set result "" for {set i 1} {$i < 6} {incr i} { set xx [lindex $xlist $i] set yy [lindex $ylist $i] set r [expr $xx - $yy] set result "$result $r" }  シフトレジスタを使って求められた差分値から  温度と時刻の瞬時値を計算して表示すると目的  のメソッドになります。  温度と時刻の瞬時値を計算するには、経過時間が必要。  経過時間は、カウンタ値$ecntに格納されているので、  数値から時刻を算出する関数を用意します。  数値から時刻に変換する関数の定義は、以下。 proc conv_time {x} { # default set result "0:00" # quotient set q [expr $x / 60] # residue set r [expr $x % 60] # set result [format "%d:%02d" $q $r] return $result }  ここまで用意したなら、メソッドの定義が可能。  メソッドのコードは以下。 proc fexec {} { # global eflag elast ecnt xexe_temp xexe_time xdif tdif ddif bdif # judge set xp0 [calc_time $xexe_time(P0)] set xp1 [calc_time $xexe_time(P1)] set xp2 [calc_time $xexe_time(P2)] set xp3 [calc_time $xexe_time(P3)] set xp4 [calc_time $xexe_time(P4)] set xp5 [calc_time $xexe_time(P5)] set xflag 0 if { $xp0 > $xp1 } { incr xflag } if { $xp1 > $xp2 } { incr xflag } if { $xp2 > $xp3 } { incr xflag } if { $xp3 > $xp4 } { incr xflag } if { $xp4 > $xp5 } { incr xflag } # message if { $xflag > 0 } { tk_messageBox -message "Time incorrect !" -type ok } else { # last count set elast $xp5 # clear counter set ecnt 0 # calculate (temperature) set xtmp "$xexe_temp(P0) $xexe_temp(P1)" set xtmp "$xtmp $xexe_temp(P2) $xexe_temp(P3)" set xtmp "$xtmp $xexe_temp(P4) $xexe_temp(P5)" set ytmp "0 $xtmp" set result "" for {set i 1} {$i < 6} {incr i} { set xx [lindex $xtmp $i] set yy [lindex $ytmp $i] set r [expr $xx - $yy] set result "$result $r" } set xdif $result # calculate (time) set xtmp "$xp0 $xp1 $xp2 $xp3 $xp4 $xp5" set ytmp "0 $xtmp" set result "" for {set i 1} {$i < 6} {incr i} { set xx [lindex $xtmp $i] set yy [lindex $ytmp $i] set r [expr $xx - $yy] set result "$result $r" } set tdif $result # calculate boundary set sum 0 set bdif "0" for {set i 0} {$i < 4} {incr i} { set xx [lindex $tdif $i] set sum [expr $sum + $xx] set bdif "$bdif $sum" } # calculate displacement set result "" for {set i 0} {$i < 5} {incr i} { set xx [lindex $xdif $i] set yy [lindex $tdif $i] set r [format "%0.1f" [expr ($xx * 1.0) / $yy]] set result "$result $r" } set ddif $result # enable set eflag 1 set ecnt 0 # loop show_time } }  メソッド中で、周期動作の手続きを起動します。  この手続きの内容は以下。 proc show_time {} { # global ecnt eflag elast # show draw_hand # handlign if { $eflag == 1 } { incr ecnt # ? complete if { $ecnt >= $elast } { set eflag 0 } } after 1000 show_time }  周期処理で表示に関係する手続きを利用。  表示に関係する手続きのコードは以下。 proc draw_hand {} { # global cPathV cTimeV cTempV eflag xexe_temp ecnt ddif bdif # show if { $eflag == 1 } { # judge block set bb [which_range $ecnt] set bbx [format "P%d" $bb] # path set cPathV [format "P%d -> P%d" $bb [expr $bb+1]] # start value set beginv $xexe_temp($bbx) # displacement set dispx [lindex $ddif $bb] set dispy [lindex $bdif $bb] # calculate set ctemp [expr $beginv + $dispx * ($ecnt - $dispy)] set ctemp [expr int($ctemp)] set cTempV [format "%d" $ctemp] # time set cTimeV [conv_time $ecnt] } else { set cPathV "" set cTimeV "0:00" set cTempV "" } }  区間で利用する直線の傾きが異なるので、計算に利用する  パラメータを、他で作成したリストから取得して使います。  ラベル、エントリーで使う文字列は「-textvariable」で  オブジェクトに渡すことができるので、該当する文字列を  更新すると、表示に反映される仕様を有効利用してます。  区間を特定するため定義した関数は以下。 proc which_range {x} { # global bdif # separate set b0 [lindex $bdif 0] set b1 [lindex $bdif 1] set b2 [lindex $bdif 2] set b3 [lindex $bdif 3] set b4 [lindex $bdif 4] # judge set result 4 if { $b0 <= $x && $x < $b1 } { set result 0 } if { $b1 <= $x && $x < $b2 } { set result 1 } if { $b2 <= $x && $x < $b3 } { set result 2 } if { $b3 <= $x && $x <= $b4 } { set result 3 } return $result }

fcancel

 ボタンのクリックで、周期処理での計算と表示を  スキップすると考えました。  周期ごとの計算をしなければよいので、フラグ制御に  してある部分で論理値の判断ができるようにします。 proc fcancel {} { # global eflag # desable set eflag 0 }  フラグの論理値で、固定文字列を表示するだけに  メソッドdraw_handを定義したので、余計なことを  考えずにすみます。

clrParameters

 ボタンのクリックで、デフォルト文字列を  2つの連想配列に格納すると考えました。  連想配列の初期化に加えて、ファイル名も  「unknown」にしておきます。 proc clrParameters {} { # global tFileName xexe_temp xexe_time # file name set tFileName "unknown" # temperature set xexe_temp(P0) 20 set xexe_temp(P1) 20 set xexe_temp(P2) 20 set xexe_temp(P3) 20 set xexe_temp(P4) 20 set xexe_temp(P5) 20 # time set xexe_time(P0) 0:00 set xexe_time(P1) 0:00 set xexe_time(P2) 0:00 set xexe_time(P3) 0:00 set xexe_time(P4) 0:00 set xexe_time(P5) 0:00 }

exit

 exitボタンの役目は、アプリケーションを終了し  制御をOSに戻すこと。exitコマンドは組込まれて  いるので、呼び出すだけになります。  ボタンオブジェクト定義のときに、メソッドも格納  してあります。 button .btnExit -font {{MS ゴシック} 16 bold} -bg gray -text "exit" -width 10 -command "exit"

目次

inserted by FC2 system