Lesson 2
Pre-lecture Materials
GUI’s with tkinters
- Article: https://realpython.com/python-gui-tkinter/
- Video: https://www.youtube.com/watch?v=VMP1oQOxfM0
Object Oriented Programming
Review of Python
What is python?
Python is a high-level object-oriented programming languageIt is also called general-purpose programming language as it is used in almost every domain we can think of as mentioned below:
Why Python Programming?
Every Programming language serves some purpose or use-case according to a domain. for example, Javascript is the most popular language amongst web developers as it gives the developer the power to handle applications via different frameworks like react, vue, angular which are used to build beautiful User Interfaces. Similarly, they have pros and cons at the same time. So if we consider python it is general-purpose which means it is widely used in every domain and the reason is it’s very simple to understand and it is scalable because the speed of development is so fast. Now you get the idea why. Besides learning python, it doesn’t require any programming background so that’s why it’s popular amongst developers as well. Python has simpler syntax to the English language and the syntax allows developers to write programs with fewer lines of code.
Indentation
Python separates its code based on indentation so you don’t need to have end statements but you indentation is very important so make sure it is correct.
Variables
There is no need to declare variable types in python as python is a smart language and can interpret the variable type based on its declaration. An example is:
My_Str = “Hello World”
Print Statement
Print(“Hello World”)
If statement
if test expression:
*code*
If-else statement
if test expression:
*code*
else:
*code*
If-elif-else statement
if test expression:
*code*
elif:
*code*
else:
*code
For loop
for val in sequence:
*loop body*
While Loop
While test_expression:
*loop body*
Break statement
break
This terminated the looping of the for or while statement it is embedded in
Continue statement
continue
This ends the loop iteration early and move to the next loop in the statement it is embedded in.
Pass statement
pass
a null statement generally used as a place holder
How to Become Better Programmer
The last but most important thing is how you get better at what programming you choose is practice practice practice. Practical knowledge only acquired by playing with things so you will get more exposure to real-world scenarios. Consistency is more important than anything because if you practice it for some days and then you did nothing then when you start again it will be difficult to practice consistently. So I request you guys to learn by doing projects so it will help you understand how things get done and important thing is to have fun at the same time.
Intro to Object Oriented Programming
What is object-oriented programming?
Object-oriented programming (OOP) is a method of structuring a program by bundling related properties and behaviors into individual objects. In this tutorial, you’ll learn the basics of object-oriented programming in Python. Conceptually, objects are like the components of a system. Think of a program as a factory assembly line of sorts. At each step of the assembly line a system component processes some material, ultimately transforming raw material into a finished product. An object contains data, like the raw or preprocessed materials at each step on an assembly line, and behavior, like the action each assembly line component performs.
What Is Object-Oriented Programming in Python?
Object-oriented programming is a programming paradigm that provides a means of structuring programs so that properties and behaviors are bundled into individual objects. For instance, an object could represent a person with properties like a name, age, and address and behaviors such as walking, talking, breathing, and running. Or it could represent an email with properties like a recipient list, subject, and body and behaviors like adding attachments and sending. Put another way, object-oriented programming is an approach for modeling concrete, real-world things, like cars, as well as relations between things, like companies and employees, students and teachers, and so on. OOP models real-world entities as software objects that have some data associated with them and can perform certain functions. Another common programming paradigm is procedural programming, which structures a program like a recipe in that it provides a set of steps, in the form of functions and code blocks, that flow sequentially in order to complete a task. The key takeaway is that objects are at the center of object-oriented programming in Python, not only representing the data, as in procedural programming, but in the overall structure of the program as well.
Define a Class in Python
Primitive data structures —like numbers, strings, and lists—are designed to represent simple pieces of information, such as the cost of an apple, the name of a poem, or your favorite colors, respectively. What if you want to represent something more complex? For example, let’s say you want to track employees in an organization. You need to store some basic information about each employee, such as their name, age, position, and the year they started working. One way to do this is to represent each employee as a list:
kirk = ["James Kirk", 34, "Captain", 2265]
spock = ["Spock", 35, "Science Officer", 2254]
mccoy = ["Leonard McCoy", "Chief Medical Officer", 2266]
There are a number of issues with this approach.
First, it can make larger code files more difficult to manage. If you reference kirk[0] several lines away from where the kirk list is declared, will you remember that the element with index 0 is the employee’s name? Second, it can introduce errors if not every employee has the same number of elements in the list. In the mccoy list above, the age is missing, so mccoy[1] will return “Chief Medical Officer” instead of Dr. McCoy’s age. A great way to make this type of code more manageable and more maintainable is to use classes.
Classes vs. Instances
Classes are used to create user-defined data structures. Classes define functions called methods, which identify the behaviors and actions that an object created from the class can perform with its data. We’ll create a Dog class that stores some information about the characteristics and behaviors that an individual dog can have. A class is a blueprint for how something should be defined. It doesn’t actually contain any data. The Dog class specifies that a name and an age are necessary for defining a dog, but it doesn’t contain the name or age of any specific dog. While the class is the blueprint, an instance is an object that is built from a class and contains real data. An instance of the Dog class is not a blueprint anymore. It’s an actual dog with a name, like Miles, who’s four years old. Put another way, a class is like a form or questionnaire. An instance is like a form that has been filled out with information. Just like many people can fill out the same form with their own unique information, many instances can be created from a single class.
How to define a Class
All class definitions start with the class keyword, which is followed by the name of the class and a colon. Any code that is indented below the class definition is considered part of the class’s body. Here’s an example of a Dog class:
class Dog:
species = "Canis familiaris"
def __init__(self, name, age):
self.name = name
self.age = age
# Instance method
def description(self):
return f"{self.name} is {self.age} years old"
# Another instance method
def speak(self, sound):
return f"{self.name} says {sound}"
The properties that all Dog objects must have are defined in a method called .__init__()
. Every time a new Dog object is created, .__init__()
sets the initial state of the object by assigning the values of the object’s properties. That is, .__init__()
initializes each new instance of the class.
You can give .__init__()
any number of parameters, but the first parameter will always be a variable called self. When a new class instance is created, the instance is automatically passed to the self parameter in .__init__()
so that new attributes can be defined on the object.
In the body of .__init__()
, there are two statements using the self variable:
- self.name = name creates an attribute called name and assigns to it the value of the name parameter.
- self.age = age creates an attribute called age and assigns to it the value of the age parameter.
Attributes created in .__init__()
are called instance attributes. An instance attribute’s value is specific to a particular instance of the class. All Dog objects have a name and an age, but the values for the name and age attributes will vary depending on the Dog instance.
On the other hand, class attributes are attributes that have the same value for all class instances. You can define a class attribute by assigning a value to a variable name outside of .__init__()
.
For example, the Dog class has a class attribute called species with the value “Canis familiaris”: Class attributes are defined directly beneath the first line of the class name and are indented by four spaces. They must always be assigned an initial value. When an instance of the class is created, class attributes are automatically created and assigned to their initial values. Use class attributes to define properties that should have the same value for every class instance. Use instance attributes for properties that vary from one instance to another.
Now that we have a Dog class, let’s create some dogs!
Instantiate an Object in Python
Creating a new object from a class is called instantiating an object. You can instantiate a new Dog object by typing the name of the class, followed by opening and closing parentheses:
To pass arguments to the name and age parameters, put values into the parentheses after the class name.
When you instantiate a Dog object, Python creates a new instance and passes it to the first parameter of .__init__()
. This essentially removes the self parameter, so you only need to worry about the name and age parameters.
After you create the Dog instances, you can access their instance attributes using dot notation:
You can access class attributes the same way.
One of the biggest advantages of using classes to organize data is that instances are guaranteed to have the attributes you expect. All Dog instances have .species, .name, and .age attributes, so you can use those attributes with confidence knowing that they will always return a value.
Although the attributes are guaranteed to exist, their values can be changed dynamically:
The key takeaway here is that custom objects are mutable by default. An object is mutable if it can be altered dynamically. For example, lists and dictionaries are mutable, but strings and tuples are immutable
Instance Methods
Instance methods are functions that are defined inside a class and can only be called from an instance of that class. Just like .__init__()
, an instance method’s first parameter is always self.
This Dog class has two instance methods:
.description()
returns a string displaying the name and age of the dog..speak()
has one parameter called sound and returns a string containing the dog’s name and the sound the dog makes.
In the above Dog class, .description() returns a string containing information about the Dog instance miles. When writing your own classes, it’s a good idea to have a method that returns a string containing useful information about an instance of the class. However, .description() isn’t the most pythonic way of doing this. Methods like init() are called dunder methods because they begin and end with double underscores. There are many dunder methods that you can use to customize classes in Python. Although too advanced a topic for a beginning Python book, understanding dunder methods is an important part of mastering object-oriented programming in Python.
Intro to GUI development with tkinter
Python has a lot of GUI frameworks, but Tkinter is the only framework that’s built into the Python standard library. Tkinter has several strengths. It’s cross-platform, so the same code works on Windows, macOS, and Linux. Visual elements are rendered using native operating system elements, so applications built with Tkinter look like they belong on the platform where they’re run.
Although Tkinter is considered the de facto Python GUI framework, it’s not without criticism. One notable criticism is that GUIs built with Tkinter look outdated. If you want a shiny, modern interface, then Tkinter may not be what you’re looking for. However, Tkinter is lightweight and relatively painless to use compared to other frameworks. This makes it a compelling choice for building GUI applications in Python, especially for applications where a modern sheen is unnecessary, and the top priority is to quickly build something that’s functional and cross-platform. Building aGUI Application With Tkinter:
The foundational element of a Tkinter GUI is the window. Windows are the containers in which all other GUI elements live. These other GUI elements, such as text boxes, labels, and buttons, are known as widgets. Widgets are contained inside of windows. The first thing you need to do is import the Python GUI Tkinter module:
>>> import tkinter as tk
A window is an instance of Tkinter’s Tk class. Go ahead and create a new window and assign it to the variable window:
>>> window = tk.Tk()
When you execute the above code, a new window pops up on your screen. How it looks depends on your operating system: Now that you have a window, you can add a widget. Use the tk.Label class to add some text to a window. Create a Label widget with the text “Hello, Tkinter” and assign it to a variable called greeting:
>>> greeting = tk.Label(text="Hello, Tkinter")
The window you created earlier doesn’t change. You just created a Label widget, but you haven’t added it to the window yet. There are several ways to add widgets to a window. Right now, you can use the Label widget’s .pack()
method:
>>> greeting.pack()
When you pack a widget into a window, Tkinter sizes the window as small as it can be while still fully encompassing the widget. Now execute the following:
>>> window.mainloop()
Nothing seems to happen, but notice that no new prompt appears in the shell. window.mainloop() tells Python to run the Tkinter event loop. This method listens for events, such as button clicks or keypresses, and blocks any code that comes after it from running until you close the window where you called the method. Go ahead and close the window you’ve created, and you’ll see a new prompt displayed in the shell.
Working With Widgets
Widgets are the elements through which users interact with your program. Each widget in Tkinter is defined by a class. Here are some of the widgets available: Widget Class Description Label - A widget used to display text on the screen Button - A button that can contain text and can perform an action when clicked Entry - A text entry widget that allows only a single line of text Text - A text entry widget that allows multiline text entry Frame - A rectangular region used to group related widgets or provide padding between widgets
You’ll see how to work with each of these in the following sections, but keep in mind that Tkinter has many more widgets than those listed here. The widget’s choice gets even more complicated when you account for a whole new set of themed widgets. In the remaining part of this tutorial, you’re only going to use Tkinter’s classic widgets, though. For now, take a closer look at the Label widget.
Displaying Text and Images With Label Widgets
Label widgets are used to display text or images. The text displayed by a Label widget can’t be edited by the user. It’s for display purposes only. As you saw in the example at the beginning of this tutorial, you can create a Label widget by instantiating the Label class and passing a string to the text parameter:
label = tk.Label(text="Hello, Tkinter")
Label widgets display text with the default system text color and the default system text background color. These are typically black and white, respectively, but you may see different colors if you’ve changed these settings in your operating system. You can control Label text and background colors using the foreground and background parameters:
label = tk.Label(
text="Hello, Tkinter",
foreground="white", # Set the text color to white
background="black" # Set the background color to black
)
There are numerous valid color names, including:
- “red”
- “orange”
- “yellow”
- “green”
- “blue”
- “purple”
If you don’t feel like typing out foreground and background all the time, then you can use the shorthand fg and bg parameters to set the foreground and background colors: label = tk.Label(text=”Hello, Tkinter”, fg=”white”, bg=”black”)
You can also control the width and height of a label with the width and height parameters:
label = tk.Label(
text="Hello, Tkinter",
fg="white",
bg="black",
width=10,
height=10
)
The width and height are measured in text units. One horizontal text unit is determined by the width of the character 0, or the number zero, in the default system font. Similarly, one vertical text unit is determined by the height of the character 0. Labels are great for displaying some text, but they don’t help you get input from a user. The next three widgets that you’ll learn about are all used to get user input. Displaying Clickable Buttons With Button Widgets Button widgets are used to display clickable buttons. You can configure them to call a function whenever they’re clicked. You’ll cover how to call functions from button clicks in the next section. For now, take a look at how to create and style a button. There are many similarities between Button and Label widgets. In many ways, a button is just a label that you can click! The same keyword arguments that you use to create and style a Label will work with Button widgets. For example, the following code creates a button with a blue background and yellow text. It also sets the width and height to 25 and 5 text units, respectively:
button = tk.Button(
text="Click me!",
width=25,
height=5,
bg="blue",
fg="yellow",
)
Getting User Input With Entry Widgets
When you need to get a little bit of text from a user, like a name or an email address, use an Entry widget. It’ll display a small text box that the user can type some text into. Creating and styling an Entry widget works pretty much exactly like with Label and Button widgets. For example, the following code creates a widget with a blue background, some yellow text, and a width of 50 text units:
entry = tk.Entry(fg="yellow", bg="blue", width=50)
The interesting bit about Entry widgets isn’t how to style them, though. It’s how to use them to get input from a user. There are three main operations that you can perform with Entry widgets:
- Retrieving text with
.get()
- Deleting text with
.delete()
- Inserting text with
.insert()
The best way to get an understanding of Entry widgets is to create one and interact with it. Open up a Python shell and follow along with the examples in this section. First, import tkinter and create a new window:
>>> import tkinter as tk
>>> window = tk.Tk()
Now create a Label and an Entry widget:
>>> label = tk.Label(text="Name")
>>> entry = tk.Entry()
The Label describes what sort of text should go in the Entry widget. It doesn’t enforce any sort of requirements on the Entry, but it tells the user what your program expects them to put there. You need to .pack() the widgets into the window so that they’re visible:
>>> label.pack()
>>> entry.pack()
Notice that Tkinter automatically centers the label above the Entry widget in the window. This is a feature of .pack(), which you’ll learn more about in later sections. Now you’ve got some text entered into the Entry widget, but that text hasn’t been sent to your program yet. You can use .get() to retrieve the text and assign it to a variable called name:
>>> name = entry.get()
>>> name
'Real Python'
You can delete text as well. This .delete() method takes an integer argument that tells Python which character to remove. For example, the code block below shows how .delete(0) deletes the first character from Entry:
>>> entry.delete(0)
Getting Multiline User Input With Text Widgets
Text widgets are used for entering text, just like Entry widgets. The difference is that Text widgets may contain multiple lines of text. With a Text widget, a user can input a whole paragraph or even several pages of text! Just like with Entry widgets, you can perform three main operations with Text widgets:
- Retrieve text with
.get()
- Delete text with
.delete()
- Insert text with
.insert()
Although the method names are the same as the Entry methods, they work a bit differently. It’s time to get your hands dirty by creating a Text widget and seeing what it can do.
>>> window = tk.Tk()
>>> text_box = tk.Text()
>>> text_box.pack()
Assigning Widgets to Frames With Frame Widgets
These are the four you’ve seen so far plus the Frame widget. Frame widgets are important for organizing the layout of your widgets in an application. Before you get into the details about laying out the visual presentation of your widgets, take a closer look at how Frame widgets work, and how you can assign other widgets to them. The following script creates a blank Frame widget and assigns it to the main application window:
import tkinter as tk
window = tk.Tk()
frame = tk.Frame()
frame.pack()
window.mainloop()
frame.pack()
packs the frame into the window so that the window sizes itself as small as possible to encompass the frame.
An empty Frame widget is practically invisible. Frames are best thought of as containers for other widgets. You can assign a widget to a frame by setting the widget’s master attribute.
Controlling Layout With Geometry Managers
Up until now, you’ve been adding widgets to windows and Frame widgets using .pack()
, but you haven’t learned what exactly this method does. Let’s clear things up! Application layout in Tkinter is controlled with geometry managers. While .pack()
is an example of a geometry manager, it isn’t the only one. Tkinter has two others:
.place()
.grid()
Each window or Frame in your application can use only one geometry manager. However, different frames can use different geometry managers, even if they’re assigned to a frame or window using another geometry manager. Start by taking a closer look at .pack()
.
The .pack()
Geometry Manager
The .pack()
geometry manager uses a packing algorithm to place widgets in a Frame or window in a specified order. For a given widget, the packing algorithm has two primary steps:
- Compute a rectangular area called a parcel that’s just tall (or wide) enough to hold the widget and fills the remaining width (or height) in the window with blank space.
- Center the widget in the parcel unless a different location is specified.
.pack()
is powerful, but it can be difficult to visualize. The best way to get a feel for.pack()
is to look at some examples. See what happens when you.pack()
three Label widgets into a Frame:
import tkinter as tk
window = tk.Tk()
frame1 = tk.Frame(master=window, width=100, height=100, bg="red")
frame1.pack()
frame2 = tk.Frame(master=window, width=50, height=50, bg="yellow")
frame2.pack()
frame3 = tk.Frame(master=window, width=25, height=25, bg="blue")
frame3.pack()
window.mainloop()
.pack()
places each Frame below the previous one by default, in the order that they’re assigned to the window.
The .place() Geometry Manager
You can use .place() to control the precise location that a widget should occupy in a window or Frame. You must provide two keyword arguments, x and y, which specify the x- and y-coordinates for the top-left corner of the widget. Both x and y are measured in pixels, not text units.
Keep in mind that the origin, where x and y are both 0, is the top-left corner of the Frame or window. So, you can think of the y argument of .place() as the number of pixels from the top of the window, and the x argument as the number of pixels from the left edge of the window.
Here’s an example of how the .place()
geometry manager works:
import tkinter as tk
window = tk.Tk()
frame = tk.Frame(master=window, width=150, height=150)
frame.pack()
label1 = tk.Label(master=frame, text="I'm at (0, 0)", bg="red")
label1.place(x=0, y=0)
label2 = tk.Label(master=frame, text="I'm at (75, 75)", bg="yellow")
label2.place(x=75, y=75)
window.mainloop()
Here’s how this code works:
- Lines 5 and 6 create a new Frame widget called
frame
, measuring 150 pixels wide and 150 pixels tall, and pack it into the window with.pack()
. - Lines 8 and 9 create a new Label called
label1
with a red background and place it inframe1
at position (0, 0). - Lines 11 and 12 create a second Label called
label2
with a yellow background and place it inframe1
at position (75, 75).
The .grid()
Geometry Manager
The geometry manager you’ll likely use most often is .grid()
, which provides all the power of .pack()
in a format that’s easier to understand and maintain.
.grid()
works by splitting a window or Frame into rows and columns. You specify the location of a widget by calling .grid()
and passing the row and column indices to the row and column keyword arguments, respectively. Both row and column indices start at 0, so a row index of 1 and a column index of 2 tells .grid()
to place a widget in the third column of the second row.
The following script creates a 3 × 3 grid of frames with Label widgets packed into them:
import tkinter as tk
window = tk.Tk()
for i in range(3):
for j in range(3):
frame = tk.Frame(
master=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=i, column=j)
label = tk.Label(master=frame, text=f"Row {i}\nColumn {j}")
label.pack()
window.mainloop()
You’re using two geometry managers in this example. Each frame is attached to window with the .grid()
geometry manager:
import tkinter as tk
window = tk.Tk()
for i in range(3):
for j in range(3):
frame = tk.Frame(
master=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=i, column=j)
label = tk.Label(master=frame, text=f"Row {i}\nColumn {j}")
label.pack()
window.mainloop()
Each label is attached to its master Frame with .pack()
:
import tkinter as tk
window = tk.Tk()
for i in range(3):
for j in range(3):
frame = tk.Frame(
master=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=i, column=j)
label = tk.Label(master=frame, text=f"Row {i}\nColumn {j}")
label.pack()
window.mainloop()
The important thing to realize here is that even though .grid()
is called on each Frame object, the geometry manager applies to the window object. Similarly, the layout of each frame is controlled with the .pack()
geometry manager.
The frames in the previous example are placed tightly next to one another. To add some space around each frame, you can set the padding of each cell in the grid. Padding is just some blank space that surrounds a widget and visually sets its content apart.
The two types of padding are external and internal padding. External padding adds some space around the outside of a grid cell. It’s controlled with two keyword arguments to .grid()
:
padx
adds padding in the horizontal direction.pady
adds padding in the vertical direction.
Both padx and pady are measured in pixels, not text units, so setting both of them to the same value will create the same amount of padding in both directions. Try to add some padding around the outside of the frames from the previous example:
import tkinter as tk
window = tk.Tk()
for i in range(3):
for j in range(3):
frame = tk.Frame(
master=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=i, column=j, padx=5, pady=5)
label = tk.Label(master=frame, text=f"Row {i}\nColumn {j}")
label.pack()
window.mainloop()
.pack()
also has padx and pady parameters. The following code is nearly identical to the previous code, except that you add five pixels of additional padding around each label in both the x and y directions:
import tkinter as tk
window = tk.Tk()
for i in range(3):
for j in range(3):
frame = tk.Frame(
master=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=i, column=j, padx=5, pady=5)
label = tk.Label(master=frame, text=f"Row {i}\nColumn {j}")
label.pack(padx=5, pady=5)
window.mainloop()
Making Your Applications Interactive
By now, you have a pretty good idea of how to create a window with Tkinter, add some widgets, and control the application layout. That’s great, but applications shouldn’t just look good—they actually need to do something! In this section, you’ll learn how to bring your applications to life by performing actions whenever certain events occur. Using Events and Event Handlers When you create a Tkinter application, you must call window.mainloop() to start the event loop. During the event loop, your application checks if an event has occurred. If so, then it’ll execute some code in response. The event loop is provided for you with Tkinter, so you don’t have to write any code that checks for events yourself. However, you do have to write the code that will be executed in response to an event. In Tkinter, you write functions called event handlers for the events that you use in your application. You’ll write your own event loop in order to better understand how Tkinter’s event loop works. That way, you can see how Tkinter’s event loop fits into your application, and which parts you need to write yourself. Assume there’s a list called events that contains event objects. A new event object is automatically appended to events every time an event occurs in your program. You don’t need to implement this updating mechanism. It just automatically happens for you in this conceptual example. Using an infinite loop, you can continually check if there are any event objects in events:
Assume that this list gets updated automatically
events = []
# Run the event loop
while True:
# If the event list is empty, then no events have occurred
# and you can skip to the next iteration of the loop
if events == []:
continue
# If execution reaches this point, then there is at least one
# event object in the event list
event = events[0]
Right now, the event loop that you’ve created doesn’t do anything with event. Let’s change that. Suppose your application needs to respond to keypresses. You need to check that event was generated by a user pressing a key on their keyboard, and if so, pass event to an event handler function for keypresses. Assume that event has a .type attribute set to the string “keypress” if the event is a keypress event object, and a .char attribute containing the character of the key that was pressed. Create a new handle_keypress() function and update your event loop code:
events = []
# Create an event handler
def handle_keypress(event):
"""Print the character associated to the key pressed"""
print(event.char)
while True:
if events == []:
continue
event = events[0]
# If event is a keypress event object
if event.type == "keypress":
# Call the keypress event handler
handle_keypress(event)
When you call window.mainloop()
, something like the above loop is run for you. This method takes care of two parts of the loop for you:
- It maintains a list of events that have occurred.
- It runs an event handler any time a new event is added to that list.
Update your event loop to use window.mainloop() instead of your own event loop:
import tkinter as tk
# Create a window object
window = tk.Tk()
# Create an event handler
def handle_keypress(event):
"""Print the character associated to the key pressed"""
print(event.char)
# Run the event loop
window.mainloop()
.mainloop()
takes care of a lot for you, but there’s something missing from the above code. How does Tkinter know when to use handle_keypress()
? Tkinter widgets have a method called .bind()
for just this purpose.
Using .bind()
To call an event handler whenever an event occurs on a widget, use .bind()
. The event handler is said to be bound to the event because it’s called every time the event occurs. You’ll continue with the keypress example from the previous section and use .bind()
to bind handle_keypress() to the keypress event:
import tkinter as tk
window = tk.Tk()
def handle_keypress(event):
"""Print the character associated to the key pressed"""
print(event.char)
# Bind keypress event to handle_keypress()
window.bind("<Key>", handle_keypress)
window.mainloop()
Here, the handle_keypress()
event handler is bound to a "<Key>"
event using window.bind()
. Whenever a key is pressed while the application is running, your program will print the character of the key pressed.
.bind()
always takes at least two arguments:
- An event that’s represented by a string of the form
"<event_name>"
, where event_name can be any of Tkinter’s events - An event handler that’s the name of the function to be called whenever the event occurs
The event handler is bound to the widget on which .bind()
is called. When the event handler is called, the event object is passed to the event handler function.
Conclusion
Tkinter is a compelling choice for a Python GUI framework because it’s built into the Python standard library, and it’s relatively painless to make applications with this framework. Now that you’ve mastered the foundations of Python GUI programming with Tkinter, the next step is to build some of your own applications. What will you create? Share your fun projects down in the comments below!
Building Our Speed Typing GUI
Now that you are prepared with the foundational knowledge, we can begin to build our preliminary speed typing test GUI. So, using everything we learned here are the steps and helpful code bits to build it. The steps to build our preliminary GUI are as follows:
- Import the necessary libraries to build the GUI a. That would be tkinter, time, threading, and random
- Define the GUI class
- Make 3-13 in the
__init__
method - Make an attribute
self.window
to define the window and its title and size a.self.window.title("title")
is how you define the title b.self.window.geometry("800x600")
is how you define the size - Create a text file and read it in using the following code
a.
self.texts = open("texts.txt", "r").read().split("\n")
- Bind the window to a frame
- Create a label and assign
text = random.choice(self.texts)
a. This assigns a random sentence from the text file to the label - Make an entry widget and bind the following event to it
a.
self.input_entry.bind("<KeyRelease>", self.start)
b. Self.start is a method we will define later - Create a label to display words per minute
- Define the reset button as following
a.
self.reset_button = tk.Button(self.frame, text = "Reset", command = self.reset, font = ("Helvetica", 18))
- Expand the frame
a.
self.frame.pack(expand=True)
- define counter attribute and a running Boolean flag
- end it with
self.root.mainloop()
- define the following methods a. start, time_thread, reset b. put place holder command pass in these methods for now
- Instantiate the GUI class at the end with no indentation to
If you are having any issues with this process feel free to email me any time for assitance. alynch@ucsbieee.org