Previous | Tutorial index | Next
Writing your first GUI program is a milestone. Unlike a terminal program that simply prints text and exits, a GUI program creates a living window that stays on your screen, responds to your mouse, and updates itself dynamically.
In this tutorial, we will dissect the minimal Tkinter application line by line. By the end, you will understand not just how to create a window, but what each line does behind the scenes, and how to customise the window for your own applications.
import tkinter as tk
tk.as tk? Tkinter has many classes (Tk, Label, Button, etc.). Using the alias prevents polluting your global namespace and makes it clear which objects come from Tkinter.from tkinter import * – this dumps all names into your namespace, which can cause accidental overwrites and makes code less readable.The tkinter module contains dozens of classes, constants, and utility functions. The most important ones we will use early on are:
tk.Tk – the root window class.tk.Label – a text/image display widget.tk.Button – a clickable button.tk.Frame – a container for other widgets.tk.Toplevel – a secondary window.pack(), grid(), place().Tk Class – Your Application's Rootroot = tk.Tk()
tk.Tk() creates an instance of the root window. This is the main window of your application.Tk instance in a program. If you need additional windows, use tk.Toplevel instead.Tk object is a singleton in practice – creating a second one will create a second independent main loop, which is rarely needed and can cause issues.The root object is not just a window – it is also the application controller. It holds:
mainloop).root.title("My First Application")
root.geometry("400x300") # width x height in pixels
root.geometry("400x300+100+50") # width x height + x_offset + y_offset
"{width}x{height}+{x}+{y}".width and height are in pixels (screen pixels).x and y are the screen coordinates of the top‑left corner of the window (relative to your display's top‑left corner). If you omit them, the window manager chooses a default position.| Method | Description |
|---|---|
root.resizable(width, height) |
True/False – allows or prevents the user from resizing the window. |
root.minsize(width, height) |
Sets the minimum size the window can be shrunk to. |
root.maxsize(width, height) |
Sets the maximum size the window can be expanded to. |
root.iconbitmap("path.ico") |
Sets the window icon (on Windows; other platforms use iconphoto). |
root.attributes("-alpha", 0.8) |
Sets transparency (0.0 fully transparent, 1.0 opaque). Windows only. |
root.attributes("-fullscreen", True) |
Makes the window full‑screen. |
import tkinter as tk
root = tk.Tk()
root.title("Advanced Config")
root.geometry("500x300+200+100")
root.resizable(False, False) # User cannot resize
root.minsize(400, 250) # Minimum size (if resizable is True)
root.maxsize(800, 600)
root.mainloop()
Labellabel = tk.Label(root, text="Hello, World!")
tk.Label is a widget class that displays text or an image.root) – this is the parent container. Every widget must be placed inside a parent (usually the root window or a frame). This creates a parent‑child hierarchy.text option – sets the string to be displayed.font, fg (foreground colour), bg (background colour), relief, justify, etc.pack(), grid(), or place()). Without this step, the widget exists in memory but is invisible.label.pack()
pack() is the simplest geometry manager. It tells Tkinter to "pack" the widget into its parent container, positioning it in a block (like stacking boxes). By default, it places widgets vertically from top to bottom, centred.pack():
side=tk.LEFT / tk.RIGHT / tk.TOP / tk.BOTTOM – changes the packing direction.padx=10, pady=10 – adds external padding around the widget.ipadx=5, ipady=5 – adds internal padding inside the widget border.fill=tk.X / tk.Y / tk.BOTH – makes the widget stretch to fill available space.expand=True – allows the widget to expand into any extra space.mainloop()mainloop() Do?root.mainloop()
mainloop(), Tkinter enters an infinite loop that:
mainloop()?root.mainloop() (or another mainloop() call).mainloop()Code placed after mainloop() will only run after the user closes the window.
This is useful for cleanup tasks (e.g., saving settings, writing logs).
Example:
root.mainloop()
print("Window closed. Goodbye!") # This prints only when the window is closed.
destroy() and quit()destroy()root.destroy()
destroy() on the root window, the mainloop() will exit automatically.quit()root.quit()
mainloop() but does not destroy the window or its widgets.destroy() to close the application properly. quit() is rarely used in simple applications.protocol Handler – Intercepting the Close ButtonWhen a user clicks the "X" (close) button on the window title bar, Tkinter's default behaviour is to destroy the window and exit mainloop(). You can override this to ask for confirmation before closing:
def on_closing():
if tk.messagebox.askokcancel("Quit", "Do you want to quit?"):
root.destroy()
root.protocol("WM_DELETE_WINDOW", on_closing)
This is an excellent way to prevent accidental data loss.
Let's annotate the complete minimal example with every concept we have covered:
import tkinter as tk # 1. Import
root = tk.Tk() # 2. Create root window
root.title("First Window") # 3. Set title
root.geometry("300x200") # 4. Set size
label = tk.Label(root, text="Hello, Tkinter!") # 5. Create label widget
label.pack() # 6. Display the label (pack it)
root.mainloop() # 7. Start the event loop
Execution flow:
mainloop()) starts the loop – the program freezes here until the window is closed.import tkinterimport tkinter as tkfrom tkinter import *include tkinterroot.set_title("My App")root.title("My App")root.name("My App")root.caption("My App")root.run()root.start()root.mainloop()root.loop()geometry("400x300") method do?
tk.Label()) but do not call any geometry manager on it (like pack()), what happens?
Tk() instances in a single program to create multiple independent windows.mainloop() function only runs for a fixed number of seconds and then stops automatically.root.destroy() method closes the window but does not stop the event loop.title() method sets the window title correctly.geometry() method automatically updates to reflect the new size.root = tk.Tk() line creates the ______________ window of the application.root.resizable(_______, _______)."300x200+50+50" passed to geometry() means width _____, height _____, and the window's top‑left corner is positioned 50 pixels from the ______________ and 50 pixels from the ______________.import tkinter as tk
root = tk.Tk
root.title("Hello)
label = tk.Label(root, text="Hi")
root.mainloop()
Task: Write a script that creates a window with the following properties:
root.winfo_screenwidth() and root.winfo_screenheight())font=("Arial", 20)).Bonus: Make the label text colour blue.
Task: Write a script that prints "Creating window..." before root = tk.Tk(), prints "Starting mainloop..." just before root.mainloop(), and prints "Window was closed." after root.mainloop(). Run the script and observe the order of print statements. Close the window to see the final print.
Task: Create a window with three labels: "Top", "Middle", "Bottom". Use pack() with different side values for each label (e.g., side=tk.TOP, side=tk.LEFT, side=tk.RIGHT). Also try adding padx=20 and pady=20 to see how spacing changes. Write down your observations about the layout.
Task: Modify the basic window so that when the user clicks the "X" button, a pop‑up message (use tk.messagebox.askyesno) asks "Are you sure you want to exit?" If the user answers "Yes", close the window; if "No", keep the window open. (Note: you will need to import tk.messagebox or from tkinter import messagebox.)
Demonstrate your deep understanding of the Tkinter root window lifecycle, widget creation, and geometry management. You will also practice reading documentation to discover new methods.
Write a complete Python script that creates a window with the following specifications:
winfo_screenwidth() and winfo_screenheight() to calculate)..ico file, or skip this if you do not have one – but explain what you would do).Label that displays your full name and student ID, with a font size of 18 and a background colour of lightyellow.pack(expand=True) or place(relx=0.5, rely=0.5, anchor=tk.CENTER)).Submit the full code, clearly commented.
root = tk.Tk() root.title("My Custom Window") sw = root.winfo_screenwidth() sh = root.winfo_screenheight()
root.geometry(f"800x500+{sw-800}+{sh-500}") root.resizable(True, True) root.minsize(500, 400) root.maxsize(1200, 900)
label = tk.Label(root, text="Your Name - Student ID", font=("Arial", 18), bg="lightyellow") label.pack(expand=True) # centering root.mainloop()
</details>
### Part B: Code Interpretation and Explanation (10 points)
Given the following code, answer the questions below:
```python
import tkinter as tk
root = tk.Tk()
root.title("Test")
root.geometry("300x300")
lbl1 = tk.Label(root, text="Label 1")
lbl2 = tk.Label(root, text="Label 2")
lbl3 = tk.Label(root, text="Label 3")
lbl1.pack(side=tk.LEFT, padx=10)
lbl2.pack(side=tk.LEFT, padx=10)
lbl3.pack(side=tk.LEFT, padx=10)
print("All labels packed.")
root.mainloop()
print("Mainloop ended.")
Questions:
lbl4 with pack(side=tk.LEFT)? Does the window resize automatically?side=tk.LEFT to side=tk.TOP for all labels, how does the layout change?print("All labels packed.") appear immediately when you run the script, but print("Mainloop ended.") only appears after closing the window?winfo Methods (5 points)Tkinter provides a family of methods prefixed with winfo_ that retrieve information about the window. Research the following methods (using Python's help() or online documentation) and explain what each does:
root.winfo_width()root.winfo_height()root.winfo_pointerx()root.winfo_children()Then, write a small script that, after the window is created but before mainloop() is called, prints the width and height. Why do they print 1 (or another small value) instead of the actual geometry size you set? (Hint: think about when the window is actually drawn.)
The width/height print 1 because the window has not yet been mapped (drawn) on the screen before mainloop() runs; the geometry is not finalised until the event loop starts. You can use root.update() before querying to force a draw, or check after mainloop() starts (but that would require an after callback).
A student submitted the following code, but it does not display the label. Explain why, and provide the corrected code.
import tkinter as tk
root = tk.Tk()
root.title("Error")
label = tk.Label(text="I am invisible")
root.mainloop()
Add a feature to your window from Part A: When the user clicks the "X" button, instead of closing immediately, the window should display a new message box that says "Thank you for using my app!" and then closes after the user clicks "OK". Write the necessary function and the protocol binding to achieve this.
| Term | Definition |
|---|---|
| Root Window | The main window of a Tkinter application, created by tk.Tk(). It holds the event loop and all widgets. |
| Widget | A GUI element like a label, button, or entry field. |
| Parent Container | The widget (or window) that contains another widget. The parent is passed as the first argument when creating a child widget. |
| Geometry Manager | A method (pack, grid, or place) that determines the size and position of widgets within their parent. |
| Event Loop | The infinite loop (mainloop()) that waits for user interactions and updates the display. |
| destroy() | A method that deletes a window and all its children, freeing memory. |
| protocol() | A method that intercepts window manager events (e.g., the close button). |
docs.python.org/3/library/tkinter.htmlLabel widget (foreground, background, font, relief, etc.).This tutorial is designed to take approximately 2–3 hours of study time, including the lab exercises and homework. Mastery of this foundational material is critical for all later Tkinter topics.