2011-07-11 24 views
1

我不能bindEscapeReturn鍵在我的Tcl/Tk代碼。以下代碼重現了該錯誤。當我打EscEnter鍵我收到以下錯誤信息:Tcl/Tk:無法綁定到轉義和返回

錯誤:無法讀取「CMD」:沒有這樣的變量

proc OkCancel { cmd } { 
    button .${cmd}.ok -text "OK" -command [list myOk $cmd ] 
    button .${cmd}.cancel -text "Cancel" -command [list myCancel .$cmd] 
    grid .${cmd}.ok .${cmd}.cancel -sticky e 

    bind .$cmd <Return> { myOk $cmd ; break } 
    bind .$cmd <Escape> { myCancel .${cmd} ; break } 
} 

proc myOk { cmd } { 
    puts "The command name is = $cmd" 
} 

proc myCancel { arg } { 
    destroy $arg 
} 

proc test { } { 
    set cmd "hello" 
    toplevel .$cmd 
    OkCancel $cmd 
} 

test 

回答

5

這是因爲當事件觸發時,腳本綁定在全球範圍內獲得eval(根據bind manual)。也就是說,如果您綁定了<Return>,字面上會執行腳本myOk $cmd ; break。因此,如果腳本運行時在全局名稱空間中不存在名爲「cmd」的變量,則會觸發您顯示的錯誤。

要解決這個問題,有幾種方法:

  • 充分利用$cmd替代在創建腳本的時間和綁定進行評估。要做到這一點,只需將{}替換爲「」以允許變量替換,也就是說,如果您要編寫bind .$cmd <Return> " myOk $cmd ; break ",則綁定腳本將爲myOK hello ; break
  • 將回調腳本轉換爲過程調用並傳遞顯式參數,如下所示:bind .$cmd <Return> [list mycallback $cmd]然後確保您已經定義了mycallback過程接受一個參數。通過這種方式,您可以編寫通用事件處理程序,通過在綁定時您需要的任何參數對其進行參數化。
  • 使用namespace code或類似的工具可以使您的腳本在指定的名稱空間中執行,該名稱空間具有指定的變量定義。

在所有情況下要注意的是,由於您的$ CMD可能在某些情況下,擴大到一個奇怪的現象,這是一個好主意,以保護整個腳本這樣的情況 - 這就是[list ...]確實在第二個例子(見this更多信息)。

+0

感謝您的詳細解釋和修復錯誤! – Anand

+0

'subst'命令可以取代'list'。因爲'list'可以在腳本的情況下做不必要的轉義。 – GrAnd

+0

@GrAnd:通常不會; 'list'通常比'subst'好,用於生成綁定腳本(和其他回調),因爲它更容易正確使用,_provided_你生成一個單一的命令。 (這個問題有一個棘手的情況,我會使用'[list ...] \; break'或甚至使用'return-code break'完成回調過程。) –