鼠标事件中的tkinter wait_variable

时间:2018-01-22 00:18:28

标签: python tkinter

我试图对我的GUI进行实时更新,但变量似乎在事件发生后更新,这意味着它会更新上一次按下按钮。我知道它与wait_variable函数有关,但文档很模糊,而另一篇关于它的帖子似乎对我没什么帮助。这是相关代码:

编辑:工作示例

来自tkinter import * 导入json import os

class GUI:
    def __init__(self,master):
        self.master = master
        self.frame = Frame(master)
        master.title("Catalogue")
        master.geometry("500x300")
        self.categories = ["Top","Bottom","Dress","Outerwear"]
        self.setup_filters()

    def setup_filters(self):
        self.filter_categs_vars = []
        self.filter_checks = []
        for i in range(len(self.categories)):
            self.filter_categs_vars.append(IntVar())
            self.filter_checks.append(Checkbutton(root,variable=self.filter_categs_vars[i],text=self.categories[i]))
            self.filter_checks[i].grid(row=7+i,column=0,sticky=W)
            self.filter_checks[i].select()
            self.filter_checks[i].bind("<ButtonRelease-1>", self.filter_categ)

    def filter_categ(self, event):
        for i in range(len(self.filter_categs_vars)):
            #self.filter_checks[i].wait_variable(self.filter_categs_vars[i])
            print(self.filter_categs_vars[i].get()) #Debug print

#START PROGRAM
global catalogue 
root = Tk()
GUI(root)
root.mainloop()

1 个答案:

答案 0 :(得分:1)

分析

对于上述问题,我认为a Minimal, Complete, and Verifiable example

import tkinter as tk


def callback(event):
    #checkbutton.wait_variable(var)
    checkbutton['text'] = var.get()

if __name__ == '__main__':
    root = tk.Tk()
    var = tk.BooleanVar()
    checkbutton = tk.Checkbutton(root, text="Check", variable=var,
                                        onvalue=True, offvalue=False)
    checkbutton.pack()
    checkbutton.bind("<ButtonRelease-1>", callback)

    root.mainloop()

这只是因为虚拟事件(例如,基于其状态设置Checkbutton的值(已选中/未选中)的事件)在附加事件后的处理。处理bind(参见最后提供的MCVE)。

有关详细信息,请参阅:https://stackoverflow.com/a/3513906/7032856

对于您提供的代码,这意味着Checkbutton的值在bind事件句柄filter_categ方法完成之前不会更改。但filter_categ除非Checkbutton的值发生变化,否则不会继续前进。

这会使您的程序停留在本地事件循环中,等待'break',只有在循环完成时才会出现'break'。感觉就像一个悖论。

查看以下示例:

import tkinter as tk
import random


def modify_var(event):
    var.set(random.choice((True, False)))

def callback(event):
    checkbutton.wait_variable(var)
    checkbutton['text'] = var.get()

if __name__ == '__main__':
    root = tk.Tk()
    var = tk.BooleanVar()
    checkbutton = tk.Checkbutton(root, text="Check", variable=var,
                                        onvalue=True, offvalue=False)
    checkbutton.pack(fill='both', expand=True)
    checkbutton.bind("<ButtonRelease-1>", callback)

    root.bind_all("<Escape>", modify_var)

    root.mainloop()

它具有与您的代码相同的矛盾行为,但唯一的例外是,当 Escape 被命中时,变量wait_variable等待,var被修改,所以本地事件循环被破坏。

解决方案

使用command option in Checkbutton

替换:

self.filter_checks[i].bind("<ButtonRelease-1>", self.filter_categ)

使用:

self.filter_checks[i]['command'] = self.filter_categ

到目前为止 是最简单的 。此外,您可以将方法定义覆盖为:

def filter_categ(self):
    ...

除非其他事件稍后使用。

其MCVE:

# By using command option in Checkbutton MCVE
import tkinter as tk


def callback():
    checkbutton['text'] = var.get()

if __name__ == '__main__':
    root = tk.Tk()
    var = tk.BooleanVar()
    checkbutton = tk.Checkbutton(root, text="Check", variable=var,
                                        onvalue=True, offvalue=False)

    checkbutton['command'] = callback

    checkbutton.pack(fill='both', expand=True)
    root.mainloop()

使用Tkinter Variable Class and, trace_add

取代:

self.filter_checks[i].bind("<ButtonRelease-1>", self.filter_categ)

使用:

self.filter_categs_vars[i].trace_add('write', self.filter_categ)

使用上面的行,trace_add将使用3个参数调用其回调函数self.filter_categ,每当它附加到的变量{{1}时,您的方法也需要接受这些参数。 ,被修改。替换:

self.filter_categs_vars[i]

使用:

def filter_categ(self, event):

其MCVE:

def filter_categ(self, *args):

通过改变事件句柄序列的顺序

# By using Tkinter Variable Class and, trace_add
import tkinter as tk


def callback(*args):
    checkbutton['text'] = var.get()

if __name__ == '__main__':
    root = tk.Tk()
    var = tk.BooleanVar()
    checkbutton = tk.Checkbutton(root, text="Check", variable=var,
                                        onvalue=True, offvalue=False)

    var.trace_add('write', callback)

    checkbutton.pack(fill='both', expand=True)
    root.mainloop()

这使得self.filter_checks[i].bind("<ButtonRelease-1>", self.filter_categ) # this line is not modified self.filter_checks[i].bindtags((self.filter_checks[i].bindtags()[1:] + self.filter_checks[i].bindtags()[:1])) 事件处理最新,因为"<ButtonRelease-1>"的变量值将在执行Checkbutton之前更改。

其MCVE:

self.filter_categ