2014-01-10 93 views
0

我正在做我自己的技術調整從this post,使用畫布與文本小部件來更好地控制滾動行爲。我的代碼出現在下面。跟蹤不工作在Python TKinter checkbutton控制

所有工作正如我想要的,但由於某種原因,我用的trace跟蹤checkbutton值不工作。在控制檯窗口中不會出現任何類型的錯誤。但是當我點擊任何一個檢查按鈕時,我沒有收到預期的打印信息(來自_cbWasClicked)。盡我所能地告訴該方法從未被調用過。

我知道這應該是一個簡單而明顯的錯誤,但我很難過。我使用了print語句來確認100 IntVars已按預期方式實例化。然後我故意拼寫.trace中的方法名稱,這次它產生了一個錯誤。所以當我抽出這些診斷調整所有應該正在工作....它只是不是。有人能告訴我我錯過了什麼嗎?

環境是Python 2.7版在Windows 7

import Tkinter as tk 

class myCheckList(tk.Frame): 
    def __init__(self, root, *args, **kwargs): 
     tk.Frame.__init__(self, root, *args, **kwargs) 
     self.root = root 
     self.vsb = tk.Scrollbar(self, orient="vertical") 
     self.canvas = tk.Canvas(self, width=200, height=290, 
           relief=tk.GROOVE,bd=3, 
           scrollregion=(0,0,0,2020), 
           yscrollcommand=self.vsb.set, 
           yscrollincrement=20) 
     basecolor = self.canvas.cget('background') 
     self.vsb.config(command=self.canvas.yview) 
     self.canvas.grid(row=0,column=0,sticky=tk.NSEW,padx=(0,0),pady=0) 
     self.vsb.grid(row=0,column=1,sticky=tk.NS,padx=(0,0),pady=0) 
     for i in range(100): 
      cbv = tk.IntVar() 
      cbv.trace('w',self._cbWasClicked) 
      cb = tk.Checkbutton(self, background=basecolor, 
           variable=cbv, 
           text="Checkbutton #%s" % i) 
      self.canvas.create_window(5,20*i+5,anchor=tk.NW,window=cb) 
     self.canvas.bind_all('<MouseWheel>', 
     lambda event: self.canvas.yview_scroll(-1*event.delta/120, tk.UNITS)) 

    def _cbWasClicked(self,*args): 
     print 'checkbox clicked' 

if __name__ == "__main__": 
    root = tk.Tk() 
    myCheckList(root).grid(row=0,column=0,sticky=tk.W,padx=0,pady=0) 
    root.mainloop() 

回答

2

發現,很多摔跤和試驗後。事實證明,在trace完美的作品時,我添加幾行到類的__init__

self.status = [] 

......然後,在循環中...

self.status.append((cb,cbv)) 

...這告訴我垃圾收集是罪魁禍首。通過創建列表並在其中存儲對象引用,它們不能被垃圾收集,因此.trace仍然有效。

1

首先,您應該在FOR循環內預先加入self.cbvcb。其次,即使這樣它只能用於最後一個複選框,因爲每次迭代都會一次又一次覆蓋變量cbv。 作爲一種解決方法,我使用了在週期前一步生成的一系列變量(self.li)。這樣,您可以將每個複選框鏈接到自己的變量:

self.li = ['cbv' + str(i) for i in range(100)] 
     for i in range(100): 
      self.li[i] = tk.IntVar() 
      self.cb = tk.Checkbutton(self, background=basecolor, 
           variable=self.li[i], 
           text="Checkbutton #%s" % i) 
      self.li[i].trace('w', self._cbWasClicked) 
      self.canvas.create_window(5,20*i+5,anchor=tk.NW,window=self.cb) 
      ... 

此代碼適用於我。 然後您需要以某種方式識別每個複選框。您可以使用內部變量name把作爲第一個參數傳遞給在trace方法callback功能(What are the arguments to Tkinter variable trace method callbacks?)做到這一點:

def _cbWasClicked(self, name, *args): 
     print('checkbox %s clicked:' % name) 

在輸出你會得到這樣的事情:

checkbox PY_VAR10 clicked: 
checkbox PY_VAR99 clicked: 
checkbox PY_VAR0 clicked: