checkbutton $w.b0 -text "Safety Check" \
-variable safety -relief flat \
-onvalue "all" \
-offvalue "none" \
-tristatevalue "partial"
The option determines the value of a checkbutton when it is neither checked (onvalue) nor unchecked (offvalue); it corresponds to the alternate visual state for display purposes. As nothing prevents you from assigning an invalid value to a checkbutton I was able to indirectly mimic the behaviour found in the original demo (see _value_changed and _safety_changed methods in code below). The screenshot on the right shows how the Safety checkbutton's alternate state looks under Windows 7.
The original demo displays the checkbutton control variables in a separate window via a See Variables button. I've chosen to display them in a separate panel along side the checkbuttons themselves.
# File: checkbuttons.py
# References:
# http://www.tcl.tk/man/tcl8.5/TkCmd/ttk_checkbutton.htm
from tkinter import *
from tkinter import ttk
from demopanels import MsgPanel, SeeDismissPanel
class CheckbuttonDemo(ttk.Frame):
def __init__(self, isapp=True, name='checkbuttondemo'):
ttk.Frame.__init__(self, name=name)
self.pack(expand=Y, fill=BOTH)
self.master.title('Checkbutton Demo')
self.isapp = isapp
self._create_widgets()
def _create_widgets(self):
if self.isapp:
MsgPanel(self,
["Four checkbuttons are displayed below. If you click on a button, ",
"it will toggle the button's selection state and set a control variable ",
"to a value indicating the state of the checkbutton.\n\n",
"The first button follows the state of the other three. ",
"If only some of the three are checked, the first button will ",
"display the 'alternate' (tri-state) mode."]
)
SeeDismissPanel(self)
self._create_demo_panel()
def _create_demo_panel(self):
demoPanel = ttk.Frame(self)
demoPanel.pack(side=TOP, fill=BOTH, expand=Y)
left = self._create_btn_panel(demoPanel) # checkbuttons
right = self._create_var_panel(demoPanel) # checkbutton variables
left.pack(side=LEFT, expand=True, padx=10, fill=BOTH)
right.pack(side=LEFT, expand=True, padx=10, fill=BOTH)
def _create_var_panel(self, parent):
# panel to display check button variable values
right = ttk.LabelFrame(parent, text='Checkbutton Control Variables')
self.vb0 = ttk.Label(right, font=('Courier', 10))
self.vb1 = ttk.Label(right, font=('Courier', 10))
self.vb2 = ttk.Label(right, font=('Courier', 10))
self.vb3 = ttk.Label(right, font=('Courier', 10))
self.vb0.pack(anchor=NW, pady=3)
self.vb1.pack(anchor=NW, pady=3)
self.vb2.pack(anchor=NW, pady=3)
self.vb3.pack(anchor=NW, pady=3)
self._show_vars()
return right
def _show_vars(self):
# set text for labels in var_panel to include the control
# variable name and current variable value
self.vb0['text'] = '{:<8} {:<8}'.format('safety:', self.safety.get())
self.vb1['text'] = '{:<8} {:<8}'.format('wipers:', self.vars[0].get())
self.vb2['text'] = '{:<8} {:<8}'.format('brakes:', self.vars[1].get())
self.vb3['text'] = '{:<8} {:<8}'.format('sober:', self.vars[2].get())
def _create_btn_panel(self, parent):
# frame to hold the check buttons
left = ttk.LabelFrame(parent, text='Checkbuttons')
# control variables linked to check buttons
self.safety = StringVar(value='none') # group monitor
wipers = IntVar()
brakes = IntVar()
sober = IntVar()
self.vars = [wipers, brakes, sober]
# check buttons
self.b0 = ttk.Checkbutton(left, text='Safety Check', variable=self.safety,
onvalue= 'all', offvalue='none', command=self._safety_changed)
b1 = ttk.Checkbutton(left, text='Wipers OK', variable=wipers, command=self._value_changed)
b2 = ttk.Checkbutton(left, text='Brakes OK', variable=brakes, command=self._value_changed)
b3 = ttk.Checkbutton(left, text='Driver Sober', variable=sober, command=self._value_changed)
# pack the buttons
self.b0.pack(side=TOP, pady=2, anchor=W)
for b in [b1, b2, b3]:
b.pack(side=TOP, pady=2, padx=15, anchor=W)
return left
def _safety_changed(self):
# all or none other check buttons selected
if self.safety.get() != 'partial':
value = 0 # deselect all
if self.safety.get() == 'all':
value = 1 # select all
# select or deselect other buttons
for i in range(len(self.vars)):
self.vars[i].set(value)
self._show_vars()
def _value_changed(self):
# get check button values
values = []
for i in range(len(self.vars)):
values.append(self.vars[i].get())
if 0 not in values: # all check buttons selected
self.safety.set('all') # set safety check button to 'all'
else:
# all not selected, set safety to 'partial'
self.safety.set(value='partial')
# change safety check button visual state
# to 'indefinite', neither checked nor empty
self.b0.state(['alternate'])
self._show_vars()
if __name__ == '__main__':
CheckbuttonDemo().mainloop(