Tkinter等待变量鼠标事件中

2024-06-26 00:21:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试对我的GUI进行一些实时更新,但是变量似乎在事件发生后会更新,这意味着它会更新之前按下的按钮。我知道它与wait_variable()函数有关,但是文档不清楚,另外一篇关于它的文章似乎对我没有帮助。以下是相关代码:

编辑:工作示例

from tkinter import *
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()

Tags: importselfmasterdefsetupguirootvars
1条回答
网友
1楼 · 发布于 2024-06-26 00:21:00

分析

对于上述问题,我认为是{a1}:

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()

发生这种情况的原因很简单,例如,根据状态设置^{值的虚拟事件(checked/unchecked),是在处理与bind相关的事件之后处理的(请参阅最后提供的MCVE)。在

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


对于您提供的代码,这意味着在bind事件句柄filter_categ方法完成之前,Checkbutton的值不会改变。但是filter_categ不会继续移动,除非Checkbutton的值被更改。在

这会使程序停留在本地事件循环中,等待'break',只有在循环完成后,'break'才会出现。感觉很矛盾。在


查看以下示例:

^{pr2}$

它具有与代码相同的悖论行为,但唯一的例外是,当Escape被命中时,变量wait_variablewaits,var被修改,因此本地事件循环被中断。在


解决方案

使用^{} option in ^{}

替换:

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, ^{}

替换:

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

有:

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

在上面这一行,trace_add将调用它的回调函数self.filter_categ,对于这三个参数,您的方法也需要接受这些参数,只要它所附加的变量self.filter_categs_vars[i]被修改。替换:

def filter_categ(self, event):

有:

def filter_categ(self, *args):

其MCVE:

# 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中,self.filter_categ执行之前,"<ButtonRelease-1>"的变量值将发生变化。在

其MCVE:

# By shifting the order of event handle sequence MCVE
import tkinter as tk


def callback(event):
    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)

    # comment the line below out to see the difference
    checkbutton.bindtags((checkbutton.bindtags()[1:] + checkbutton.bindtags()[:1]))

    root.mainloop()

相关问题 更多 >