We covered some of the major simple widgets in Tkinter. There are a few more used less regularly: radio buttons, checkboxes, sliders, and spinners. This lesson, we’ll look at those widgetsand make a better power panel.
Control Variables
We used control variables in the Button
, Entry
and Label
widgets. The control variable in a button and label controlled the text and title programmatically using the textvariable
attribute. In those cases, the control variable is optional. For the controls we are going to discuss, control variables are mandatory to work properly. Unlike Python variables, control variables are typed — they are classes of the Tkinter module. There are three types:
IntVar
– integers and boolean values represented by 0 and 1DoubleVar
– floating point numbersStringVar
– strings
Declare a control variable by assigning it to the proper constructor:
my_bool = IntVar() my_int = IntVar() my_float = DoubleVar() my_String =StringVar()
In the widget there is an attribute assigned to the control variable, such as value
, textvariable
or variable
. The system will use the value to change the control or give you a value from the control.
When assigning values, control variables are not Python variables. They are Tkinter objects. As objects, they have true getters and setters. Trying to use simple assignment will lead to bugs or exceptions:
#DON’T do this a_String = my_String my_String = ‘Hello World’ #DO this instead: aString= my_String.get() myString.set(‘Hello World’)
Making a Starting Control Panel
We have made buttons and labels in an earlier post. We configured them in another. We made buttons with images in the last post. To start this lesson and review what we covered before, here is a control panel with image buttons:
#Steve_sampler_02 #a demo program to show many Tkinter widgets #05-01-14 from tkinter import * #make the window root=Tk() root.title("Steve's Control Widget Sampler") #make the frame frame = Frame(root) frame.grid(row=0, column=0) #—————— Controller ————- #control variables label1_text = StringVar() def infoPressed(): label1_text.set('About') def okPressed(): label1_text.set('Start') #—————— View —————— #label label1_text.set('Off') label_1 = Label(frame, textvariable = label1_text) label_1.grid(column = 0,row = 0) # info button button_1 = Button(frame, text = 'info',command= infoPressed) button_1.grid(column = 0 , row = 5) button_1_image= PhotoImage(file = 'glass_button_info.gif') button_1.configure(image = button_1_image, relief = FLAT) #ok button button_2 = Button(frame, text = 'Ok', command = okPressed) button_2.grid(column = 1 , row = 5) button_2_image= PhotoImage(file = 'glass_button_OK.gif') button_2.configure(image = button_2_image, relief = FLAT) #exit button button_3 = Button(frame, text = 'Exit', command = quit) button_3.grid(column = 2 , row = 5) button_3_image= PhotoImage(file = 'glass_button_exit.gif') button_3.configure(image = button_3_image, relief = FLAT) #main loop mainloop()
We set up three buttons and a label. The label uses a control variable, and changes the message depending on the button we click. Each button uses one of the images below:
You can make your own or download these buttons. Place the files in the same directory as your program. We set relief
to FLAT
to make the buttons look better. Build and run and you will see this:
Make a Multi-line label with Message
The Message
widget is a label which allows for multiple lines. Like C and Java, a new line escape sequence \n
in a string will make for a new line. Message
widgets set up like a label in almost every other aspect. Place this code above the label code:
#message message1_text.set('Message Area \n Here‘) message1 = Message(frame) message1.grid(column = 1, row = 0, rowspan = 2,columnspan = 3, sticky = EW) message1.configure(textvariable = message1_text, aspect = 150, width = 240)
We have another control variable for this widget. Add this to our control variable declaration
message1_text = StringVar()
Build and run. We now have a second message area that shows two lines.
Make a Check Button
In earlier lessons we used a button as a toggle. Most people use a Checkbutton
to do this. Check buttons usually have some visual indicator of the status on or off. Add this code above the message widget code:
# checkbutton checkButton_1 = Checkbutton(frame,text = 'On',variable = isOn, command = onOffChanged) checkButton_1.grid(column = 0, row = 1)
The Checkbutton
has a mandatory control variable. Declare the control variable with the other variables.
isOn = IntVar()
Checkbutton
uses an integer control variable as a boolean value. By default, false is 0 and true is 1. We did not initialize this control variable. Checkbutton sets this variable to 0 as a default. This code has a command attribute. Add a function below the other controller functions:
def onOffChanged(): if isOn.get()== 1: mytext = 'System On' else: mytext = 'System Off' label1_text.set(mytext)
We use the value of the check button to change the label. Click it back and forth a few times.
Make a Spin Box
The spin box is an incremental counter with up and down buttons. Add the following code above the Checkbutton
code.
#spinbox spin1 = Spinbox(frame, textvariable = spin1_text ) spin1.grid(column = 3, row = 5) spin1.configure(from_ =0, to = 10, increment = 0.5, width = 5) spin1.configure(font = ('Sans', '18', 'bold'))
Spin boxes use a range of values stored as a string. Add the following to the control variables.
spin1_text=StringVar()
Specify the range of values with the from_
and the to
attributes. The increment
is the amount added or subtracted from the count in the spin box. The width
is the number of digits to show in the spin box. Build, run and try out the current version of the control panel.
Make Radio Buttons
Radio button share the Check boxes on/off status. Unlike the Checkbox
, radio buttons work together, so that only one is on at one time. This works well for small lists of choices. Radio buttons use an attribute variable
assigned to a control variable. Control variables are instantiated IntVar()
or a StringVar()
. Add this to our control variables:
radio_value = StringVar()
With the value
attribute, set a value for each radio button. By default, that value sets the title text for the button. There are text
, textvariable
and image
attributes if you want something other than the value as the title text. As radio buttons work as a group, you can make all the radio buttons using one instance variable for the widgets. Before adding the widgets, initialize the default value for the radio button. Add this code above the check button code:
#radiobuttons radio_value.set(‘white') radioButton = Radiobutton(frame,value = 'white',variable = radio_value) radioButton.grid(column = 0, row = 4) radioButton.configure(text = 'white') #radiobuttons radioButton = Radiobutton(frame,value = 'red',variable = radio_value) radioButton.grid(column = 1, row = 4) radioButton.configure(text = 'red') #radiobuttons radioButton = Radiobutton(frame,value = 'blue',variable = radio_value) radioButton.grid(column = 2, row = 4) radioButton.configure(text = 'blue') #radiobuttons radioButton = Radiobutton(frame,value = 'gray',variable = radio_value) radioButton.grid(column = 3, row = 4) radioButton.configure(text = 'gray')
Build and run. Each radio button, when pressed, indicates the user clicked it.
Make a Scale Slider
Our last widget is a scale slider, which combines attribute of many of the widgets. Scale sliders are either horizontal or vertical sliders limited to a range of values with some interval between their values. Scale sliders, like spinners have from_
and to
attributes to define the range. Instead of a increment, the attribute is a tickinterval
to indicate the resolution of the slider. The control value for a scale slider is a number, and can be either a IntVar()
or a DoubleVar()
. If declared as a StringVar(
) the value returned will be the string representation of the number. Add this control variable to the control variable declarations:
scale1_text = StringVar()
One new attribute is orient
. A value of HORIZONTAL
will make a horizontal slider. A value of VERTICAL
will make a vertical scale slider. VERTICAL
is the default. Add this code above the code for the radio buttons:
#scale scale1_text.set('0') scale1 = Scale(frame,variable = scale1_text, command = sliderChanged) scale1.grid(column =0, row =7, columnspan = 4, sticky = EW) scale1.configure(orient = HORIZONTAL, from_ = 0, to = 25, tickinterval = 5)
The code includes command=sliderChanged
. Add this below our other controller functions:
def sliderChanged(myScale ): #needs a parameter if(isOn.get() == 1): #changeColors() voltage = myScale time = spin1_text.get() #value of our spinner mystring = 'Power Panel!! \n Voltage at: '+ voltage+ 'V\n Time at: ' + time message1_text.set(mystring) label1_text.set('Change '+ voltage + 'V') else: label1_text.set("System Off") message1_text.set('Standby Mode')
Scale sliders always pass a parameter of its value to the specified command. The function called must have one parameter or will cause an exception. This parameter is equal to the control variable. If the function uses the value and nothing else does, the control variable is not necessary. You can also use a getter to the scale slider instance if you don’t want a variable at all. For example
voltage = scale1.get()
works as well as a control variable.
In this function, there is a line of code to get the value of our spinner from its control variable.
time = spin1_text.get()
When we slide, the display will show a voltage for the scale slider and a time for the spinner. The code also uses our Checkbox
. The user must turn on the control panel before anything interesting happens. Build and run:
We left one line in sliderChanged()
commented out, a function for the radio buttons to change colors. Add this as the first function in our grouping of functions.
def changeColors(): color = radio_value.get() message1.configure(background = color) if color == 'red': message1.configure(foreground = 'yellow') elif color == 'blue': message1.configure(foreground = 'white') else: message1.configure(foreground = 'black')
This function sets the background color by the radio button and adjusts the foreground color to contrast. Remove the comment from sliderChanged()
. Replace the okPressed()
function with this to tie everything together:
def okPressed(): if(isOn.get() == 1): label1_text.set('Running...') changeColors() voltage = scale1_text.get() time = spin1_text.get() mystring = 'Power Panel!! \n Voltage at: '+ voltage+ 'V\n Time at: ' + time message1_text.set(mystring) else: label1_text.set('Turn system on') message1_text.set('Standby Mode')
Build and run:
We have now covered most of the simple controls. There are some that are more complex such as scroll boxes, drop downs, and menu bars. Before we cover those, our next step is to show a more advanced but consistent way to do everything we just did — with style.
Leave a Reply