【问题标题】:How to program follow-up actions when the state of a ttk.Checkbutton widget changes?当 ttk.Checkbutton 小部件的状态发生变化时,如何编写后续操作?
【发布时间】:2021-11-11 15:11:07
【问题描述】:

我注意到ttk.Checkbuttons 小部件中的一种行为。也就是说,任何应用到此小部件的绑定或事件处理程序始终发生在小部件的 command 选项方法/函数执行之前。

意义:

  1. 鉴于ttk.Checkbuttons 的状态更改是由command 选项方法/函数执行的,通过事件处理程序访问的ttk.Checkbuttons['variable'] 的值将始终是旧状态而不是新状态由小部件的 command 选项方法/函数定义的状态。

  2. 在事件处理程序中更改ttk.Checkbuttons['variable'] 的值会破坏小部件的command 选项方法/函数的性能。因此,ttk.Checkbuttons['variable'] 应该在小部件的command 选项方法/函数中设置。

问题

鉴于上述情况,那么将事件处理程序绑定到 ttk.Checkbuttons 小部件的目的是什么?

事件处理程序在事件发生时执行,例如当<ButtonRelease-1> 发生在ttk.Checkbutton 小部件上时。如果我想根据小部件的状态设计后续操作,我无法通过事件处理程序来实现,因为小部件instate 尚未更新。一种解决方法是假设在事件处理程序中获得的小部件 instatevariable 与报告的 instate 或 variable.get() 值相反。然而,这样的做法似乎很冒昧。

当状态发生变化时,我应该如何使用ttk.Checkbutton 的事件处理程序来编写后续操作?还是应该不使用,只使用widgetscommand选项方法/函数,根据widget的状态设计后续动作?

【问题讨论】:

  • 您是否尝试对变量使用after?trace_add? :P 顺便说一句,我喜欢你的问题。你问我苦苦挣扎的事情。 :D
  • @Atlas435 我添加了我在使用.trace_add() 方法作为答案时学到的见解。也许它对你有帮助。 ;)

标签: python tkinter ttk


【解决方案1】:

鉴于上述情况,那么将事件处理程序绑定到 ttk.Checkbuttons 小部件的目的是什么?

这样您就可以定义自己的行为来覆盖默认行为。

当状态发生变化时,我应该如何使用 ttk.Checkbutton 的事件处理程序来编写后续操作?

一种解决方案是使用事件处理程序。相反,在关联变量上设置跟踪。使用变量跟踪,您的回调函数将在设置变量后调用,并且在每次值更改时调用,即使更改是由事件以外的其他原因完成的。

cb_var = tk.StringVar(value="off")
cb = ttk.Checkbutton(root, variable=cb_var, onvalue="on", offvalue="off", text="Ready?")
cb_var.trace_add('write', callback)

另一种解决方案是在类的绑定标签之后创建一个自定义绑定标签。

例子:

cb_var = tk.StringVar(value="off")
cb = ttk.Checkbutton(root, variable=cb_var, onvalue="on", offvalue="off", text="Ready?")
tag = f'custom_{cb}'
cb.bindtags((cb, 'TCheckbutton', '.', tag, 'all'))
cb.bind_class(tag, "<ButtonRelease-1>", callback)

通过上述方法,在该事件被小部件类上的默认绑定处理后,将在 &lt;ButtonRelease-1&gt; 按钮上调用回调。如果这样做,您还应该以类似的方式将绑定添加到空格键,因为您还可以使用空格键设置复选按钮的值。

有关绑定标签的另一个示例以及更多关于它们如何工作的讨论,请参阅this answer 问题How to bind self events in Tkinter Text widget after it will binded by Text widget?。另外,请参阅this answer 问题Basic query regarding bindtags in tkinter

【讨论】:

  • 我在这里学到了一些新东西。我想问when='tail',因为我自己还没有弄清楚。 link to docs
  • @Atlas435:when 属性不适用于此处。这是event_generate 的一个选项,而这个答案不使用event_generate
  • 感谢您的回复。现在我知道了check= ttk.Checkbutton(root,text='Test', command=lambda:[check.event_generate('&lt;&lt;pseudo_event&gt;&gt;',when='tail'), p_command(),],
  • @Atlas435:我不认为你认为的那样。
  • 我最好问个问题。
【解决方案2】:

以下是我使用 .trace_add() 方法和使用 @987654321 共享的类的绑定标签之后的自定义绑定标签的发现和结论@。希望能给 tkinter 用户带来好处。


相反,在关联变量上设置跟踪。有一个变量 跟踪,你的回调函数将在变量有后被调用 已设置,并且每次值更改时都会调用,即使 更改不是由事件完成的。

我发现了以下内容:

  1. .trace_add() 方法执行的回调将始终在ttk.Checkbutton 小部件的命令选项方法/函数之前。
  2. 另外,如果ttk.Checkbutton的变量值在ttk.Checkbutton小部件的命令选项方法/函数执行期间发生变化,.trace_add()方法的回调将在小部件的命令选项方法的中途执行/功能。意思是,.trace_add() 方法的回调可以在一个完整的事件流中多次执行。

为了说明以上几点,下面是我编写的测试代码的打印输出语句。测试代码包含 4 个 ttk.Checkbutton 小部件,在打开时分别具有控制变量值 B1B2B3B4,在关闭时分别具有“0”值。单击时,ttk.Checkbutton 将在开启和关闭状态之间切换。但是,必须始终打开至少一个ttk.Checkbutton。最初,这些按钮都是打开的。接下来,依次单击这些按钮以关闭。语句### Callback #### 是从.trace_add() 方法的回调中打印出来的。从### Command Trigger 0 ###### Command Trigger 1 ### 的打印输出发生在ttk.Checkbutton 小部件的command 选项的方法/函数的开头和结尾。

打印报表:

# B1 ttk.Checkbutton clicked on
#++ Callback ++++  Button variable values = ['0', 'B2', 'B3', 'B4']  3
### Command Trigger 0 ### Button variable values = ('0', 'B2', 'B3', 'B4') 3
cb=.!App.!checkbutton   text=B1   variable=B1 Checkbutton variable
nchosen != 0
### Command Trigger 1 ### Button variable values = ('0', 'B2', 'B3', 'B4') 3

# B2 ttk.Checkbutton clicked on
#++ Callback ++++  Button variable values = ['0', '0', 'B3', 'B4']  2
### Command Trigger 0 ### Button variable values = ('0', '0', 'B3', 'B4') 2
cb=.!App.!checkbutton2   text=B2   variable=B2 Checkbutton variable
nchosen != 0
### Command Trigger 1 ### Button variable values = ('0', '0', 'B3', 'B4') 2

# B3 ttk.Checkbutton clicked on
#++ Callback ++++  Button variable values = ['0', '0', '0', 'B4']  1
### Command Trigger 0 ### Button variable values = ('0', '0', '0', 'B4') 1
cb=.!App.!checkbutton3   text=B3   variable=B3 Checkbutton variable
nchosen != 0
### Command Trigger 1 ### Button variable values = ('0', '0', '0', 'B4') 1

# B4 ttk.Checkbutton clicked on
#++ Callback ++++  Button variable values = ['0', '0', '0', '0']  0
### Command Trigger 0 ### Button variable values = ('0', '0', '0', '0') 0
cb=.!App.!checkbutton4   text=B4   variable=B4 Checkbutton variable
nchosen == 0

#++ Callback ++++  Button variable values = ['0', '0', '0', 'B4']  1
### Command Trigger 1 ### Button variable values = ('0', '0', '0', 'B4') 1

意义:

由于.trace_add() 方法的回调总是先于ttk.Checkbutton 小部件的command 选项的方法/函数的执行,并且可以在ttk.Checkbutton 小部件的@987654347 的方法/函数执行期间发生@选项在每个事件流期间,.trace_add()方法的回调内容必须预见到这种情况。


另一种解决方案是创建一个自定义绑定标签 类的绑定标签。

...,回调将在 该事件被默认绑定处理后的按钮 小部件类。

我相信术语回调 应该被称为事件处理程序。在任何情况下,这种安排的打印输出声明如下所示。 证明事件处理程序将始终在ttk.Checkbutton 小部件的命令选项方法/功能完全执行后执行。 与使用.trace_add() 方法的流程不同,@987654351 的执行@widget 的命令选项方法/功能永远不会中断。

打印报表:

# B1 ttk.Checkbutton clicked on
### Command Trigger 0 ### Button variable values = ('0', 'B2', 'B3', 'B4') 3
cb=.!App.!checkbutton   text=B1   variable=jpg variable
nchosen != 0
### Command Trigger 1 ### Button variable values = ('0', 'B2', 'B3', 'B4') 3
#&& run_event_handler &&&&  Button variable values = ('0', 'B2', 'B3', 'B4') 3

# B2 ttk.Checkbutton clicked on
### Command Trigger 0 ### Button variable values = ('0', '0', 'B3', 'B4') 2
cb=.!App.!checkbutton2   text=B2   variable=B2 variable
nchosen != 0
### Command Trigger 1 ### Button variable values = ('0', '0', 'B3', 'B4') 2
#&& run_event_handler &&&&  Button variable values = ('0', '0', 'B3', 'B4') 2

# B3 ttk.Checkbutton clicked on
### Command Trigger 0 ### Button variable values = ('0', '0', '0', 'B4') 1
cb=.!App.!checkbutton3   text=B3   variable=B3 variable
nchosen != 0
### Command Trigger 1 ### Button variable values = ('0', '0', '0', 'B4') 1
#&& run_event_handler &&&&  Button variable values = ('0', '0', '0', 'B4') 1

# B4 ttk.Checkbutton clicked on
### Command Trigger 0 ### Button variable values = ('0', '0', '0', '0') 0
cb=.!App.!checkbutton4   text=B4   variable=tif variable
nchosen == 0
### Command Trigger 1 ### Button variable values = ('0', '0', '0', 'B4') 1
#&& run_event_handler &&&&  Button variable values = ('0', '0', '0', 'B4') 1

结论:

  1. 我需要在执行后续流程之前完全配置ttk.Checkbutton 小部件。因此,使用小部件的command 选项方法/函数首先配置小部件并使用小部件类的绑定标签之后的自定义绑定标签来执行后续过程被认为是最好的方法。
  2. 在小部件上发生事件后,观察以下方法和处理程序的执行顺序:
    1. .bind() 方法的事件处理程序
    2. 小部件的command 选项的方法/功能
    3. .bind_class() 方法的事件处理程序,该方法具有自定义绑定标记,位于小部件类的绑定标记之后。
  3. .trace_add() 方法的回调总是发生在第 2 项执行之前。此外,它也可能发生在第 2 项和第 3 项执行过程中。

【讨论】:

    猜你喜欢
    • 2023-03-06
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-21
    • 1970-01-01
    相关资源
    最近更新 更多