Below are my findings and conclusion from using .trace_add()
method and from using custom binding tag that comes after the binding tag of the class that were shared by @ByranOakley. Hope that it can benefit tkinter users.
Instead, set a trace on the associated variable. With a variable
trace, your callback function will be called after the variable has
been set, and will be called every time the value changes even when
the change is done by something other than an event.
I discovered the following:
- The callback executed by the
.trace_add()
method will always precede the ttk.Checkbutton
widget's command option method/function.
- In addition, if the value of the variable of the
ttk.Checkbutton
changes during the execution of the ttk.Checkbutton
widget's command option method/function, the callback of the .trace_add()
method will execute midway of the widget's command option method/function. Meaning, the callback of the .trace_add()
method can be executed more than once during one complete event flow.
To illustrate the above points, below is the printout statements of a test code that I have written. The test code contains 4 ttk.Checkbutton
widgets with control variable values B1
, B2
, B3
, B4
, respectively, when switched on and '0' value when switched off. When clicked, the ttk.Checkbutton
will be toggled between on and off condition. However, at least one ttk.Checkbutton
must always be switched on. Initially, these buttons are all switched on. Next, these buttons are clicked sequentially to switched off. The statement ### Callback ####
is printout from the callback of the .trace_add()
method. The printouts from ### Command Trigger 0 ###
to ### Command Trigger 1 ###
occurs from the start and end of the method/function of the ttk.Checkbutton
widget's command
option.
Printout Statements:
# 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
Significance:
As the callback of the .trace_add()
method always precede the execution of the method/function of the ttk.Checkbutton
widget's command
option and can occur during the execution of the method/function of the ttk.Checkbutton
widget's command
option during each event flow, the content of the callback of the .trace_add()
method must anticipate such an occurrence.
Another solution is to create a custom binding tag that comes after
the binding tag of the class.
..., the callback will be called on the
button after that event has been processed by the default binding on
the widget class.
I believe the term callback should be called an event handler instead. In any case, printout statements of such an arrangement is shown below. It evidences that the event handler will always execute after the ttk.Checkbutton
widget's command option method/function is fully executed,. Unlike the process flow from using a .trace_add()
method, the execution of the ttk.Checkbutton
widget's command option method/function is never interrupted.
Printout Statements:
# 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
Conclusions:
- My need was to fully configure the
ttk.Checkbutton
widgets before executing follow-up process(s). As such, using the widget's command
option method/function to first configure the widget and using customised binding tags that comes after the binding tag of the widget class to perform follow-up process(s) were found to be the best approach.
- After an event occurs at the widget, the sequence of the execution of the following methods and handlers was observed:
- event handler of the
.bind()
method
- method/function of the widget's
command
option
- event handler of the
.bind_class()
method that has a custom binding tag that comes after the binding tag of the class of the widget.
- The callback of a
.trace_add()
method always occurred before the execution of item 2. Furthermore, it can also occur in the midst of executing items 2 and 3.