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.
We used control variables in the
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 1
DoubleVar– floating point numbers
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
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’)
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()
You can make your own or download these buttons. Place the files in the same directory as your program. We set
FLAT to make the buttons look better. Build and run and you will see this:
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()
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)
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.
The spin box is an incremental counter with up and down buttons. Add the following code above the
#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.
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.
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()
value attribute, set a value for each radio button. By default, that value sets the title text for the button. There are
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')
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
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.
If you are making your own stuff, doing your own work and trying to sell it in the market, most advice isn't enough. You want it to work. You want to sell your works to those who most are touched by them. This newsletter is for you. I am one of those people like you, creative, independent and maybe a little bit crazy to the outside world. I'll talk about writing good apps for Apple platforms, the tools and API's to get there. Along the way I will show you how to become you best creative self. I will show you how to build and create, and make some money at it too.
Get exclusive content, new post notifications, tips and more in A Slice of App Pie.
This site may include links that provide monetary compensation to the owners of this site.