Day 28: Basic GUI Development with Tkinter
🐍 Day 28: Basic GUI Development with Tkinter
1. Learning Objectives
By the end of Day 28, you will be able to:
- Understand event‑driven programming and how GUIs differ from console apps
- Create windows, labels, buttons, entry fields, and text areas with Tkinter
- Arrange widgets using geometry managers (
pack,grid,place) - Respond to user interactions with event handlers and callbacks
- Build a fully functional desktop application (calculator, to‑do list)
- Style widgets with colours, fonts, and padding
2. Concept Explanation
2.1 What is Tkinter? — Python's Built‑in GUI Toolkit
Tkinter is Python's standard GUI (Graphical User Interface) library. It's a thin wrapper around Tcl/Tk, which has been battle‑tested for decades. Tkinter ships with every Python installation — no extra installs needed.
Why Tkinter?
| Strength | Detail |
|---|---|
| Built‑in | Works out of the box with any Python install |
| Cross‑platform | Windows, macOS, Linux — same code |
| Simple | Ideal for learning GUI concepts |
| Sufficient | Perfect for internal tools, small apps, prototypes |
Alternatives (for later exploration):
- PyQt / PySide — professional, feature‑rich, steeper learning curve
- Kivy — multi‑touch, mobile‑friendly
- Dear PyGui — modern, fast, GPU‑accelerated
2.2 Event‑Driven Programming — A New Paradigm
Console programs run sequentially — line by line, waiting for input() when needed. GUI programs are event‑driven — they start, draw the window, then enter an event loop that waits for the user to click, type, or move the mouse.
Console flow: GUI flow:
─────► start ─────► start
│ ├─► draw window
├─► input() └─► event loop (infinite)
├─► process ├─► user clicks button → handler()
├─► print() ├─► user types text → handler()
└─► end └─► user closes window → exit
Your code reacts to events by binding functions (callbacks) to widgets.
2.3 Your First Tkinter Window
import tkinter as tk
# Create the main window
root = tk.Tk()
root.title("My First GUI")
root.geometry("400x300") # width x height in pixels
# Create a label widget
label = tk.Label(root, text="Hello, Tkinter!", font=("Arial", 16))
label.pack(pady=20) # add it to the window with vertical padding
# Start the event loop
root.mainloop()
Every Tkinter app follows this skeleton:
- Create the root window (
tk.Tk()). - Create widgets (Label, Button, Entry, etc.) and attach them to a parent.
- Arrange widgets with a geometry manager (
pack,grid, orplace). - Start the event loop (
root.mainloop()).
2.4 Core Widgets — Your GUI Building Blocks
| Widget | Purpose | Example |
|---|---|---|
Label | Display text or image | tk.Label(root, text="Name:") |
Button | Clickable button | tk.Button(root, text="Submit", command=callback) |
Entry | Single‑line text input | tk.Entry(root, width=30) |
Text | Multi‑line text area | tk.Text(root, height=5, width=40) |
Checkbutton | On/off checkbox | tk.Checkbutton(root, text="Agree") |
Radiobutton | One‑of‑many selection | tk.Radiobutton(root, text="Option 1", variable=var, value=1) |
Listbox | Scrollable list | tk.Listbox(root) |
Frame | Container for other widgets | tk.Frame(root) |
Scale | Slider control | tk.Scale(root, from_=0, to=100) |
Every widget's constructor takes:
parent— the container it belongs to (usuallyrootor aFrame)- Configuration options like
text,width,height,font,bg,fg
2.5 Geometry Managers — Arranging Widgets
Tkinter offers three layout systems:
pack() — Stack widgets vertically or horizontally
label1 = tk.Label(root, text="Top")
label1.pack(side="top", fill="x")
label2 = tk.Label(root, text="Bottom")
label2.pack(side="bottom")
| Option | Effect |
|---|---|
side | "top", "bottom", "left", "right" |
fill | "x" (horizontal), "y" (vertical), "both" |
expand | True to use extra space |
padx, pady | External padding in pixels |
ipadx, ipady | Internal padding |
grid() — Row‑column layout (most versatile)
tk.Label(root, text="Username:").grid(row=0, column=0, sticky="e")
tk.Entry(root).grid(row=0, column=1)
tk.Label(root, text="Password:").grid(row=1, column=0, sticky="e")
tk.Entry(root, show="*").grid(row=1, column=1)
tk.Button(root, text="Login").grid(row=2, column=0, columnspan=2)
| Option | Effect |
|---|---|
row, column | Position (0‑indexed) |
sticky | "n", "s", "e", "w" — which edge to stick to |
columnspan, rowspan | Span multiple cells |
padx, pady | Internal padding |
place() — Absolute positioning (rarely used)
tk.Label(root, text="X: 100, Y: 50").place(x=100, y=50)
💡 Recommendation:
grid()is the most flexible. Use it for forms and most layouts.pack()is fine for simple stacks. Avoidplace()for responsive designs.
2.6 Event Handling — Making Widgets Interactive
The command parameter — simplest way to attach a callback to a Button:
def say_hello():
label.config(text="Hello, World!")
btn = tk.Button(root, text="Click Me", command=say_hello)
Retrieving data from widgets:
def submit():
name = entry.get() # Get text from Entry
text_area.insert("end", f"{name}\n") # Append to Text widget
entry.delete(0, "end") # Clear the Entry
entry = tk.Entry(root)
btn = tk.Button(root, text="Submit", command=submit)
Binding additional events:
def on_key_press(event):
print(f"Key pressed: {event.char}")
root.bind("<Key>", on_key_press) # Bind to all key presses
entry.bind("<Return>", lambda e: submit()) # Enter key triggers submit
Common event patterns:
| Event | Description |
|---|---|
"<Button-1>" | Left mouse click |
"<Double-Button-1>" | Double click |
"<Return>" | Enter key |
"<Key>" | Any key press |
"<FocusIn>" | Widget receives focus |
"<FocusOut>" | Widget loses focus |
2.7 Changing Widget Appearance
label = tk.Label(
root,
text="Styled Label",
font=("Helvetica", 14, "bold"),
fg="white", # foreground (text) colour
bg="#333333", # background colour
padx=10,
pady=5,
relief="ridge", # border style
borderwidth=2
)
Colour names: "red", "blue", "green", "white", "black", "gray" — or hex codes like "#FF5733".
2.8 Message Boxes and Dialogs
from tkinter import messagebox
def confirm_exit():
answer = messagebox.askyesno("Exit", "Are you sure you want to quit?")
if answer:
root.destroy()
# Types of message boxes:
# messagebox.showinfo(title, message)
# messagebox.showwarning(title, message)
# messagebox.showerror(title, message)
# messagebox.askyesno(title, message)
# messagebox.askokcancel(title, message)
3. Code Examples
Example 1: Simple Login Form
import tkinter as tk
from tkinter import messagebox
def login():
username = entry_user.get()
password = entry_pass.get()
if username == "admin" and password == "1234":
messagebox.showinfo("Success", "Login successful!")
else:
messagebox.showerror("Error", "Invalid credentials")
root = tk.Tk()
root.title("Login")
root.geometry("300x200")
tk.Label(root, text="Username:").grid(row=0, column=0, padx=10, pady=10, sticky="e")
entry_user = tk.Entry(root, width=25)
entry_user.grid(row=0, column=1, padx=10)
tk.Label(root, text="Password:").grid(row=1, column=0, padx=10, pady=10, sticky="e")
entry_pass = tk.Entry(root, show="*", width=25)
entry_pass.grid(row=1, column=1, padx=10)
tk.Button(root, text="Login", command=login, width=12).grid(row=2, column=0, columnspan=2, pady=15)
root.mainloop()
Example 2: Simple Calculator
import tkinter as tk
def click(key):
if key == "=":
try:
result = eval(display.get())
display.delete(0, "end")
display.insert("end", str(result))
except:
display.delete(0, "end")
display.insert("end", "Error")
elif key == "C":
display.delete(0, "end")
else:
display.insert("end", key)
root = tk.Tk()
root.title("Calculator")
display = tk.Entry(root, font=("Arial", 20), justify="right", width=15)
display.grid(row=0, column=0, columnspan=4, padx=5, pady=5)
buttons = [
"7", "8", "9", "/",
"4", "5", "6", "*",
"1", "2", "3", "-",
"C", "0", "=", "+",
]
for i, text in enumerate(buttons):
row = i // 4 + 1
col = i % 4
tk.Button(root, text=text, width=5, height=2,
font=("Arial", 14),
command=lambda t=text: click(t)).grid(row=row, column=col, padx=2, pady=2)
root.mainloop()
Example 3: To‑Do List App
import tkinter as tk
from tkinter import messagebox
def add_task():
task = entry.get().strip()
if task:
listbox.insert("end", task)
entry.delete(0, "end")
else:
messagebox.showwarning("Warning", "Task cannot be empty.")
def remove_task():
try:
selected = listbox.curselection()[0]
listbox.delete(selected)
except IndexError:
messagebox.showwarning("Warning", "Select a task to remove.")
def clear_tasks():
if messagebox.askyesno("Confirm", "Remove all tasks?"):
listbox.delete(0, "end")
root = tk.Tk()
root.title("To‑Do List")
root.geometry("400x400")
frame_top = tk.Frame(root)
frame_top.pack(pady=10)
entry = tk.Entry(frame_top, width=30, font=("Arial", 12))
entry.pack(side="left", padx=5)
entry.bind("<Return>", lambda e: add_task())
tk.Button(frame_top, text="Add", command=add_task, width=8).pack(side="left")
listbox = tk.Listbox(root, font=("Arial", 12), selectmode="single")
listbox.pack(fill="both", expand=True, padx=10, pady=5)
frame_bottom = tk.Frame(root)
frame_bottom.pack(pady=10)
tk.Button(frame_bottom, text="Remove", command=remove_task, width=10).pack(side="left", padx=5)
tk.Button(frame_bottom, text="Clear All", command=clear_tasks, width=10).pack(side="left", padx=5)
root.mainloop()
4. Hands-On Exercises
Exercise 1: Temperature Converter
Build a GUI with an Entry for Celsius, a Button labelled "Convert", and a Label that displays the result in Fahrenheit. Formula: F = C × 9/5 + 32. Handle invalid input gracefully.
Exercise 2: Counter App
Create a simple app with a Label showing a number (start at 0) and two Button widgets: "Increment" and "Decrement". Clicking them should update the label. Bonus: change the label colour to green when positive, red when negative.
Exercise 3: Registration Form
Build a form with fields: Name, Email, Age, and Password. Add a "Submit" button that validates all fields are non‑empty and age is a number. Show a success/failure message using messagebox.
Exercise 4: Word Counter
Create a Text widget where the user can type or paste text. Below it, show a Label that updates in real time showing the character count and word count. (Hint: bind to "<KeyRelease>")
Exercise 5: Colour Picker
Add three Scale widgets (sliders) for Red, Green, Blue values (0–255). A Frame or Label should display the resulting colour in real time. Show the hex colour code below it (e.g., #4A7B3C).
5. Applied Challenge Task 🏗️
Personal Finance Tracker GUI
Transform the CLI Expense Tracker (Day 23) into a desktop GUI application using Tkinter.
Requirements:
Main Window: A well‑laid‑out window with sections for input and display.
Input Form:
Entryfor amount (validate positive number)ComboboxorOptionMenufor category (Food, Transport, Entertainment, Utilities, Other)Entryfor description (optional)Entryfor date (default to today)- "Add Expense" button
Expense List:
- Use a
Treeview(fromtkinter.ttk) to display all expenses in columns: ID, Date, Category, Amount, Description. - Add a scrollbar.
- Highlight expenses over a configurable threshold (e.g., > $100 in red).
- Use a
Controls:
"Delete Selected" button — removes the selected row from DB and display.
"Refresh" button — reloads data from the database.
"Summary" button — opens a new window showing:
- Total spent
- Total per category (bar chart using simple Canvas rectangles)
- Number of expenses
Data Persistence:
- Use SQLite (same schema as Day 23).
- Load expenses on startup.
- Save on every add/delete.
Polish:
- Use
ttkthemed widgets for a modern look. - Add keyboard shortcuts (
Enterto add,Deleteto remove). - Handle window close event to confirm exit.
- Use
Stretch goals:
- Add a "Budget" feature: set a monthly budget per category, show warnings when exceeded.
- Export the expense list as CSV or JSON via a File menu.
- Add a date filter (two
Entryfields for start/end date).
6. Brief Review Summary
| Concept | Key Points |
|---|---|
| Tkinter | Python's built‑in GUI toolkit; no install needed |
| Event loop | root.mainloop() — waits for and dispatches events |
| Widgets | Label, Button, Entry, Text, Listbox, Frame, Scale, etc. |
| Geometry managers | pack() (stack), grid() (row‑column), place() (absolute) |
| Callbacks | command= parameter or .bind() for events |
| messagebox | showinfo, showwarning, showerror, askyesno |
| Treeview | ttk.Treeview — table‑like display with columns |
7. Preview of Next Topic — Day 29
Tomorrow we’ll prepare your projects for the real world:
- Packaging and Distribution — turning your code into installable packages
setup.py/pyproject.toml— defining project metadata- Virtual environments — review of
venvandpip freeze - Git Integration — version control basics,
.gitignore, README - Running Python anywhere —
pyinstallerfor standalone executables
🎯 Your Action Items for Day 28:
- ✅ Complete all 5 exercises
- ✅ Build the Personal Finance Tracker GUI challenge
- ✅ Experiment with
ttkthemed widgets for a more modern look - ✅ Try binding different events (
<Key>,<Button-3>,<MouseWheel>)
Comments
Post a Comment
Leave us your comments here...