【问题标题】:Trace not working on Python TKinter checkbutton control跟踪不适用于 Python TKinter 复选按钮控件
【发布时间】:2014-01-10 22:07:37
【问题描述】:

我正在对this post 的技术进行自己的调整,使用画布与文本小部件来更好地控制滚动行为。我的代码如下所示。

一切都按我的意愿工作,但由于某种原因,我用来跟踪检查按钮值的trace 不起作用。控制台窗口中不会显示任何类型的错误。但是当我单击任何一个复选按钮时,我没有收到预期的打印消息(来自_cbWasClicked)。据我所知,该方法从未被调用过。

我知道这一定是一个简单而明显的错误,但我很难过。我已经使用 print 语句来确认 100 IntVars 已按预期实例化。然后我故意把.trace中的方法名拼错了,这次就报错了。因此,当我拉出这些诊断调整时,所有应该都可以工作....只是不行。有人可以告诉我我缺少什么吗?

环境是 Windows 7 上的 Python 2.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()

【问题讨论】:

    标签: python-2.7 tkinter


    【解决方案1】:

    经过多次摔跤和试验,找到了它。事实证明,当我在类的 __init__ 中添加几行时,trace 可以完美运行:

    self.status = []
    

    ...然后,在循环内部...

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

    ...这告诉我垃圾收集是罪魁祸首。通过创建一个列表并将对象引用存储在其中,它们不能被垃圾回收,因此.trace 仍然有效。

    【讨论】:

      【解决方案2】:

      首先,您应该在 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:
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-11-21
        • 2016-05-23
        • 1970-01-01
        • 2014-09-13
        • 1970-01-01
        • 2017-12-18
        • 2019-06-17
        • 2020-07-31
        相关资源
        最近更新 更多