History and Architecture of Tkinter
Tkinter was created in the early 1990s as a Python wrapper for the Tk GUI toolkit. Tk, in turn, was developed by John Ousterhout at the University of California, Berkeley. Over more than 30 years, the library has evolved significantly while preserving its philosophy of simplicity and reliability.
The architecture of Tkinter is based on event‑driven programming. The core component is the main event loop, which waits for user actions and responds by invoking the appropriate callback functions.
Installation and First Run
Checking Tkinter Availability
Tkinter is part of the Python standard library and usually does not require a separate installation. To verify its availability, run:
python -c "import tkinter; print('Tkinter is available')"
Installation on Different Operating Systems
Windows: Tkinter is installed automatically with Python.
macOS: Included in the standard Python distribution.
Linux (Ubuntu/Debian):
sudo apt-get install python3-tk
Linux (CentOS/RHEL):
sudo yum install tkinter
# or for newer versions
sudo dnf install python3-tkinter
Creating Your First Application
import tkinter as tk
# Create the main window
window = tk.Tk()
window.title("My First Application")
window.geometry("400x300")
window.resizable(True, True)
# Start the main loop
window.mainloop()
Main Tkinter Components
Root Window
The root window is the base element of any Tkinter application. All other widgets must be placed inside it or inside its child windows.
import tkinter as tk
root = tk.Tk()
root.title("Window Title")
root.geometry("800x600+100+50") # width x height + offset_x + offset_y
root.minsize(300, 200) # minimum size
root.maxsize(1200, 800) # maximum size
root.configure(bg='lightblue') # background color
Core Widgets and Their Usage
Label
Label is used to display text or images that the user cannot edit.
label = tk.Label(
window,
text="Information label",
font=("Arial", 14),
fg="blue",
bg="white",
anchor="center"
)
label.pack(pady=10)
Button
Button is an interactive element that triggers actions.
def button_click():
print("Button pressed!")
button = tk.Button(
window,
text="Click Me",
command=button_click,
font=("Arial", 12),
bg="green",
fg="white",
width=15,
height=2
)
button.pack(pady=5)
Entry
Entry is intended for single‑line text input.
entry_var = tk.StringVar()
entry = tk.Entry(
window,
textvariable=entry_var,
font=("Arial", 12),
width=30
)
entry.pack(pady=5)
# Retrieve the value
def get_entry_value():
value = entry_var.get()
print(f"Entered: {value}")
Text
Text provides a multi‑line editable text area.
text_widget = tk.Text(
window,
height=10,
width=50,
font=("Courier", 10),
wrap=tk.WORD
)
text_widget.pack(pady=10)
# Insert text
text_widget.insert(tk.END, "Initial text\n")
# Get all text
def get_text_content():
content = text_widget.get("1.0", tk.END)
return content
Checkbutton
Checkbutton lets the user choose a yes/no option.
check_var = tk.BooleanVar()
checkbox = tk.Checkbutton(
window,
text="I agree to the terms",
variable=check_var,
command=lambda: print(f"State: {check_var.get()}")
)
checkbox.pack(pady=5)
Radiobutton
Radiobutton is used for selecting one option from a group.
radio_var = tk.StringVar(value="option1")
radio1 = tk.Radiobutton(
window,
text="Option 1",
variable=radio_var,
value="option1"
)
radio2 = tk.Radiobutton(
window,
text="Option 2",
variable=radio_var,
value="option2"
)
radio1.pack()
radio2.pack()
Listbox
Listbox displays a list of selectable items.
listbox = tk.Listbox(
window,
height=6,
selectmode=tk.SINGLE
)
items = ["Item 1", "Item 2", "Item 3"]
for item in items:
listbox.insert(tk.END, item)
listbox.pack(pady=10)
def on_select(event):
selection = listbox.curselection()
if selection:
selected_item = listbox.get(selection[0])
print(f"Selected: {selected_item}")
listbox.bind("<<ListboxSelect>>", on_select)
OptionMenu
OptionMenu creates a drop‑down list of choices.
option_var = tk.StringVar(value="Select an option")
options = ["Option A", "Option B", "Option C"]
option_menu = tk.OptionMenu(window, option_var, *options)
option_menu.pack(pady=10)
Scale
Scale lets the user pick a numeric value within a defined range.
scale_var = tk.DoubleVar()
scale = tk.Scale(
window,
from_=0,
to=100,
orient=tk.HORIZONTAL,
variable=scale_var,
label="Choose a value"
)
scale.pack(pady=10)
Canvas
Canvas is intended for drawing graphical elements.
canvas = tk.Canvas(
window,
width=400,
height=300,
bg="white"
)
canvas.pack(pady=10)
# Draw various shapes
canvas.create_line(0, 0, 400, 300, fill="red", width=2)
canvas.create_rectangle(50, 50, 150, 100, fill="blue", outline="black")
canvas.create_oval(200, 50, 300, 150, fill="green")
canvas.create_text(200, 200, text="Canvas text", font=("Arial", 16))
Widget Geometry Managers
Pack Manager
Pack arranges widgets sequentially in the chosen direction.
# Vertical packing
label1 = tk.Label(window, text="Label 1", bg="red")
label1.pack(side=tk.TOP, fill=tk.X, padx=5, pady=2)
label2 = tk.Label(window, text="Label 2", bg="green")
label2.pack(side=tk.TOP, fill=tk.X, padx=5, pady=2)
# Horizontal packing
button1 = tk.Button(window, text="Button 1")
button1.pack(side=tk.LEFT, padx=5)
button2 = tk.Button(window, text="Button 2")
button2.pack(side=tk.RIGHT, padx=5)
Grid Manager
Grid places widgets in a table of rows and columns.
# Simple login form
tk.Label(window, text="Username:").grid(row=0, column=0, sticky="e", padx=5, pady=5)
login_entry = tk.Entry(window)
login_entry.grid(row=0, column=1, padx=5, pady=5)
tk.Label(window, text="Password:").grid(row=1, column=0, sticky="e", padx=5, pady=5)
password_entry = tk.Entry(window, show="*")
password_entry.grid(row=1, column=1, padx=5, pady=5)
login_button = tk.Button(window, text="Log In")
login_button.grid(row=2, column=0, columnspan=2, pady=10)
Place Manager
Place allows precise positioning of widgets by coordinates.
button1 = tk.Button(window, text="Absolute Position")
button1.place(x=50, y=100)
button2 = tk.Button(window, text="Relative Position")
button2.place(relx=0.5, rely=0.5, anchor="center")
Event Handling
Basic Event Handling
Tkinter supports a wide range of events from the keyboard, mouse, and system.
def on_key_press(event):
print(f"Key pressed: {event.keysym}")
def on_mouse_click(event):
print(f"Mouse click at: ({event.x}, {event.y})")
def on_window_close():
if messagebox.askyesno("Confirmation", "Close the application?"):
window.destroy()
# Bind events
window.bind("<Key>", on_key_press)
window.bind("<Button-1>", on_mouse_click)
window.protocol("WM_DELETE_WINDOW", on_window_close)
Key Event Types
Keyboard:
<Key>– any key<Return>– Enter<Escape>– Escape<Control-s>– Ctrl+S
Mouse:
<Button-1>– left mouse button<Button-3>– right mouse button<Double-Button-1>– double‑click<Motion>– mouse movement
Window:
<Configure>– window resize<FocusIn>– focus gained<FocusOut>– focus lost
Working with Dialog Windows
Standard Message Dialogs
from tkinter import messagebox
# Information message
messagebox.showinfo("Info", "Operation completed successfully")
# Warning
messagebox.showwarning("Warning", "Proceed with caution")
# Error
messagebox.showerror("Error", "An error occurred")
# Yes/No question
result = messagebox.askyesno("Confirm", "Continue?")
# Yes/No/Cancel question
result = messagebox.askyesnocancel("Save", "Save changes?")
File Selection Dialogs
from tkinter import filedialog
# Open file
filename = filedialog.askopenfilename(
title="Select a file",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
# Save file
filename = filedialog.asksaveasfilename(
title="Save As",
defaultextension=".txt",
filetypes=[("Text files", "*.txt")]
)
# Choose directory
directory = filedialog.askdirectory(title="Select a folder")
Simple Input Dialogs
from tkinter import simpledialog
# String input
name = simpledialog.askstring("Input", "Enter your name:")
# Integer input
age = simpledialog.askinteger("Input", "Enter your age:", minvalue=0, maxvalue=120)
# Float input
price = simpledialog.askfloat("Input", "Enter the price:", minvalue=0.0)
Additional Windows (Toplevel)
def create_new_window():
new_window = tk.Toplevel(window)
new_window.title("Additional Window")
new_window.geometry("300x200")
new_window.grab_set() # Modal window
tk.Label(new_window, text="This is a new window").pack(pady=20)
close_button = tk.Button(
new_window,
text="Close",
command=new_window.destroy
)
close_button.pack(pady=10)
create_window_button = tk.Button(
window,
text="Open New Window",
command=create_new_window
)
create_window_button.pack(pady=20)
Working with Tkinter Variables
Tkinter provides special variable classes for binding data to widgets.
# Different variable types
string_var = tk.StringVar(value="Initial value")
int_var = tk.IntVar(value=10)
double_var = tk.DoubleVar(value=3.14)
boolean_var = tk.BooleanVar(value=True)
# Bind to widgets
entry = tk.Entry(window, textvariable=string_var)
scale = tk.Scale(window, variable=int_var, from_=0, to=100)
checkbutton = tk.Checkbutton(window, variable=boolean_var)
# Track changes
def on_variable_change(*args):
print(f"New value: {string_var.get()}")
string_var.trace("w", on_variable_change)
Creating Menus
Main Menu
def new_file():
print("New file")
def open_file():
filename = filedialog.askopenfilename()
if filename:
print(f"Opened file: {filename}")
def save_file():
print("Save file")
def exit_app():
window.quit()
def about():
messagebox.showinfo("About", "Text editor v1.0")
# Create the main menu
menubar = tk.Menu(window)
# "File" menu
file_menu = tk.Menu(menubar, tearoff=0)
file_menu.add_command(label="New", command=new_file, accelerator="Ctrl+N")
file_menu.add_command(label="Open", command=open_file, accelerator="Ctrl+O")
file_menu.add_command(label="Save", command=save_file, accelerator="Ctrl+S")
file_menu.add_separator()
file_menu.add_command(label="Exit", command=exit_app, accelerator="Ctrl+Q")
# "Help" menu
help_menu = tk.Menu(menubar, tearoff=0)
help_menu.add_command(label="About", command=about)
# Add menus to the menubar
menubar.add_cascade(label="File", menu=file_menu)
menubar.add_cascade(label="Help", menu=help_menu)
# Set the menu for the window
window.config(menu=menubar)
# Keyboard shortcuts
window.bind("<Control-n>", lambda e: new_file())
window.bind("<Control-o>", lambda e: open_file())
window.bind("<Control-s>", lambda e: save_file())
Context Menu
def show_context_menu(event):
context_menu.post(event.x_root, event.y_root)
def copy_text():
print("Copy")
def paste_text():
print("Paste")
# Create the context menu
context_menu = tk.Menu(window, tearoff=0)
context_menu.add_command(label="Copy", command=copy_text)
context_menu.add_command(label="Paste", command=paste_text)
# Bind to right‑click
window.bind("<Button-3>", show_context_menu)
Styling and ttk
Using ttk for a Modern Look
from tkinter import ttk
# Create a style
style = ttk.Style()
style.theme_use('clam') # modern theme
# Configure styles
style.configure(
"Custom.TButton",
font=("Arial", 12),
foreground="white",
background="blue"
)
# Use ttk widgets
ttk_button = ttk.Button(
window,
text="Modern Button",
style="Custom.TButton"
)
ttk_button.pack(pady=10)
# Progress bar
progress = ttk.Progressbar(
window,
length=300,
mode='determinate'
)
progress.pack(pady=10)
progress['value'] = 50
# Combobox
combo = ttk.Combobox(
window,
values=["Option 1", "Option 2", "Option 3"],
state="readonly"
)
combo.pack(pady=10)
Table of Tkinter Methods and Functions
| Category | Method / Function | Description | Example |
|---|---|---|---|
| Main Classes | |||
Tk() |
Creates the main window | root = tk.Tk() |
|
Toplevel() |
Creates an additional window | new_win = tk.Toplevel(root) |
|
mainloop() |
Starts the main event loop | root.mainloop() |
|
| Widgets | |||
Label() |
Text label | tk.Label(root, text="Text") |
|
Button() |
Button | tk.Button(root, text="OK", command=func) |
|
Entry() |
Entry field | tk.Entry(root, width=20) |
|
Text() |
Multi‑line text area | tk.Text(root, height=10) |
|
Checkbutton() |
Checkbutton | tk.Checkbutton(root, text="Option") |
|
Radiobutton() |
Radiobutton | tk.Radiobutton(root, text="Choice") |
|
Listbox() |
Listbox | tk.Listbox(root, height=5) |
|
Scale() |
Scale | tk.Scale(root, from_=0, to=100) |
|
Canvas() |
Canvas for drawing | tk.Canvas(root, width=400, height=300) |
|
Frame() |
Widget container | tk.Frame(root, relief="solid") |
|
Menu() |
Menu | tk.Menu(root) |
|
OptionMenu() |
Drop‑down menu | tk.OptionMenu(root, var, *options) |
|
| Geometry Management | |||
pack() |
Sequential placement | widget.pack(side=tk.TOP, fill=tk.X) |
|
grid() |
Table placement | widget.grid(row=0, column=1) |
|
place() |
Absolute positioning | widget.place(x=100, y=50) |
|
| Events | |||
bind() |
Bind an event handler | widget.bind("<Button-1>", handler) |
|
unbind() |
Unbind an event handler | widget.unbind("<Button-1>") |
|
focus_set() |
Set focus | widget.focus_set() |
|
| Variables | |||
StringVar() |
String variable | var = tk.StringVar(value="text") |
|
IntVar() |
Integer variable | var = tk.IntVar(value=10) |
|
DoubleVar() |
Float variable | var = tk.DoubleVar(value=3.14) |
|
BooleanVar() |
Boolean variable | var = tk.BooleanVar(value=True) |
|
| Widget Methods | |||
get() |
Retrieve value | entry.get() |
|
set() |
Set value | var.set("new value") |
|
insert() |
Insert text | text.insert(tk.END, "text") |
|
delete() |
Delete text | text.delete("1.0", tk.END) |
|
config() / configure() |
Change properties | widget.config(text="new text") |
|
destroy() |
Destroy widget | widget.destroy() |
|
| Dialogs | |||
messagebox.showinfo() |
Information dialog | messagebox.showinfo("Title", "Message") |
|
messagebox.showwarning() |
Warning dialog | messagebox.showwarning("Attention", "Message") |
|
messagebox.showerror() |
Error dialog | messagebox.showerror("Error", "Message") |
|
messagebox.askyesno() |
Yes/No question | result = messagebox.askyesno("?", "Message") |
|
filedialog.askopenfilename() |
Open‑file dialog | file = filedialog.askopenfilename() |
|
filedialog.asksaveasfilename() |
Save‑file dialog | file = filedialog.asksaveasfilename() |
|
simpledialog.askstring() |
String input dialog | text = simpledialog.askstring("Input", "?") |
|
| Window Geometry | |||
geometry() |
Size and position | root.geometry("800x600+100+50") |
|
minsize() |
Minimum size | root.minsize(300, 200) |
|
maxsize() |
Maximum size | root.maxsize(1200, 800) |
|
resizable() |
Allow resizing | root.resizable(True, False) |
|
title() |
Window title | root.title("My Application") |
Practical Application Examples
Simple Calculator
import tkinter as tk
from tkinter import messagebox
class Calculator:
def __init__(self):
self.window = tk.Tk()
self.window.title("Calculator")
self.window.geometry("300x400")
self.window.resizable(False, False)
self.expression = ""
self.result_var = tk.StringVar()
self.create_widgets()
def create_widgets(self):
# Result display
result_frame = tk.Frame(self.window)
result_frame.pack(fill=tk.X, padx=5, pady=5)
result_entry = tk.Entry(
result_frame,
textvariable=self.result_var,
font=("Arial", 16),
justify="right",
state="readonly"
)
result_entry.pack(fill=tk.X)
# Buttons
button_frame = tk.Frame(self.window)
button_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
buttons = [
['C', '/', '*', 'Del'],
['7', '8', '9', '-'],
['4', '5', '6', '+'],
['1', '2', '3', '='],
['0', '.', '', '']
]
for i, row in enumerate(buttons):
for j, text in enumerate(row):
if text:
if text == '0':
btn = tk.Button(
button_frame,
text=text,
font=("Arial", 14),
command=lambda t=text: self.button_click(t)
)
btn.grid(row=i, column=j, columnspan=2, sticky="nsew", padx=1, pady=1)
else:
btn = tk.Button(
button_frame,
text=text,
font=("Arial", 14),
command=lambda t=text: self.button_click(t)
)
btn.grid(row=i, column=j, sticky="nsew", padx=1, pady=1)
# Configure grid
for i in range(5):
button_frame.grid_rowconfigure(i, weight=1)
for j in range(4):
button_frame.grid_columnconfigure(j, weight=1)
def button_click(self, char):
if char == 'C':
self.expression = ""
elif char == 'Del':
self.expression = self.expression[:-1]
elif char == '=':
try:
result = eval(self.expression)
self.expression = str(result)
except:
messagebox.showerror("Error", "Invalid expression")
self.expression = ""
else:
self.expression += char
self.result_var.set(self.expression)
def run(self):
self.window.mainloop()
# Run the calculator
if __name__ == "__main__":
calc = Calculator()
calc.run()
Text Editor
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import font
class TextEditor:
def __init__(self):
self.window = tk.Tk()
self.window.title("Text Editor")
self.window.geometry("800x600")
self.current_file = None
self.is_modified = False
self.create_menu()
self.create_toolbar()
self.create_text_area()
self.create_status_bar()
self.window.protocol("WM_DELETE_WINDOW", self.on_closing)
def create_menu(self):
menubar = tk.Menu(self.window)
# File menu
file_menu = tk.Menu(menubar, tearoff=0)
file_menu.add_command(label="New", command=self.new_file, accelerator="Ctrl+N")
file_menu.add_command(label="Open", command=self.open_file, accelerator="Ctrl+O")
file_menu.add_command(label="Save", command=self.save_file, accelerator="Ctrl+S")
file_menu.add_command(label="Save As", command=self.save_as_file)
file_menu.add_separator()
file_menu.add_command(label="Exit", command=self.on_closing)
# Edit menu
edit_menu = tk.Menu(menubar, tearoff=0)
edit_menu.add_command(label="Undo", command=self.undo, accelerator="Ctrl+Z")
edit_menu.add_command(label="Redo", command=self.redo, accelerator="Ctrl+Y")
edit_menu.add_separator()
edit_menu.add_command(label="Cut", command=self.cut, accelerator="Ctrl+X")
edit_menu.add_command(label="Copy", command=self.copy, accelerator="Ctrl+C")
edit_menu.add_command(label="Paste", command=self.paste, accelerator="Ctrl+V")
menubar.add_cascade(label="File", menu=file_menu)
menubar.add_cascade(label="Edit", menu=edit_menu)
self.window.config(menu=menubar)
# Keyboard shortcuts
self.window.bind("<Control-n>", lambda e: self.new_file())
self.window.bind("<Control-o>", lambda e: self.open_file())
self.window.bind("<Control-s>", lambda e: self.save_file())
def create_toolbar(self):
toolbar = tk.Frame(self.window, relief=tk.RAISED, bd=1)
toolbar.pack(side=tk.TOP, fill=tk.X)
# Toolbar buttons
new_btn = tk.Button(toolbar, text="New", command=self.new_file)
new_btn.pack(side=tk.LEFT, padx=2, pady=2)
open_btn = tk.Button(toolbar, text="Open", command=self.open_file)
open_btn.pack(side=tk.LEFT, padx=2, pady=2)
save_btn = tk.Button(toolbar, text="Save", command=self.save_file)
save_btn.pack(side=tk.LEFT, padx=2, pady=2)
def create_text_area(self):
# Text area with scrollbars
text_frame = tk.Frame(self.window)
text_frame.pack(fill=tk.BOTH, expand=True)
self.text_area = tk.Text(
text_frame,
wrap=tk.WORD,
undo=True,
font=("Consolas", 12)
)
scrollbar_y = tk.Scrollbar(text_frame, orient=tk.VERTICAL, command=self.text_area.yview)
scrollbar_x = tk.Scrollbar(text_frame, orient=tk.HORIZONTAL, command=self.text_area.xview)
self.text_area.config(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)
self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y)
scrollbar_x.pack(side=tk.BOTTOM, fill=tk.X)
# Track changes
self.text_area.bind("<KeyPress>", self.on_text_change)
self.text_area.bind("<Button-1>", self.update_status)
self.text_area.bind("<KeyRelease>", self.update_status)
def create_status_bar(self):
self.status_bar = tk.Label(
self.window,
text="Ready",
relief=tk.SUNKEN,
anchor=tk.W
)
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
def new_file(self):
if self.check_save_changes():
self.text_area.delete("1.0", tk.END)
self.current_file = None
self.is_modified = False
self.update_title()
def open_file(self):
if self.check_save_changes():
filename = filedialog.askopenfilename(
title="Open File",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if filename:
try:
with open(filename, 'r', encoding='utf-8') as file:
content = file.read()
self.text_area.delete("1.0", tk.END)
self.text_area.insert("1.0", content)
self.current_file = filename
self.is_modified = False
self.update_title()
except Exception as e:
messagebox.showerror("Error", f"Failed to open file:\n{str(e)}")
def save_file(self):
if self.current_file:
try:
content = self.text_area.get("1.0", tk.END + "-1c")
with open(self.current_file, 'w', encoding='utf-8') as file:
file.write(content)
self.is_modified = False
self.update_title()
self.status_bar.config(text="File saved")
except Exception as e:
messagebox.showerror("Error", f"Failed to save file:\n{str(e)}")
else:
self.save_as_file()
def save_as_file(self):
filename = filedialog.asksaveasfilename(
title="Save As",
defaultextension=".txt",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if filename:
self.current_file = filename
self.save_file()
def check_save_changes(self):
if self.is_modified:
result = messagebox.askyesnocancel(
"Save",
"Document has been modified. Save changes?"
)
if result is True:
self.save_file()
return not self.is_modified
elif result is False:
return True
else:
return False
return True
def on_text_change(self, event=None):
self.is_modified = True
self.update_title()
self.window.after_idle(self.update_status)
def update_title(self):
filename = self.current_file if self.current_file else "Untitled"
modified = " *" if self.is_modified else ""
self.window.title(f"{filename}{modified} - Text Editor")
def update_status(self, event=None):
# Cursor position
cursor_pos = self.text_area.index(tk.INSERT)
line, column = cursor_pos.split('.')
# Word and character count
content = self.text_area.get("1.0", tk.END + "-1c")
word_count = len(content.split())
char_count = len(content)
status_text = f"Line: {line} | Column: {column} | Words: {word_count} | Chars: {char_count}"
self.status_bar.config(text=status_text)
def undo(self):
try:
self.text_area.edit_undo()
except tk.TclError:
pass
def redo(self):
try:
self.text_area.edit_redo()
except tk.TclError:
pass
def cut(self):
try:
self.text_area.event_generate("<<Cut>>")
except tk.TclError:
pass
def copy(self):
try:
self.text_area.event_generate("<<Copy>>")
except tk.TclError:
pass
def paste(self):
try:
self.text_area.event_generate("<<Paste>>")
except tk.TclError:
pass
def on_closing(self):
if self.check_save_changes():
self.window.destroy()
def run(self):
self.window.mainloop()
# Run the editor
if __name__ == "__main__":
editor = TextEditor()
editor.run()
Frequently Asked Questions
How do I change a widget’s font?
widget.config(font=("Arial", 12, "bold"))
# or
custom_font = font.Font(family="Times", size=14, weight="normal")
widget.config(font=custom_font)
How can I disable a widget?
widget.config(state="disabled")
# To enable again
widget.config(state="normal")
How do I get a widget’s size?
width = widget.winfo_width()
height = widget.winfo_height()
How do I center a window on the screen?
def center_window(window, width, height):
screen_width = window.winfo_screenwidth()
screen_height = window.winfo_screenheight()
x = (screen_width - width) // 2
y = (screen_height - height) // 2
window.geometry(f"{width}x{height}+{x}+{y}")
center_window(root, 800, 600)
How can I keep a window always on top?
window.attributes("-topmost", True)
How do I create a full‑screen application?
window.attributes("-fullscreen", True)
# Exit fullscreen
window.bind("<Escape>", lambda e: window.attributes("-fullscreen", False))
How do I add an icon to my application?
window.iconbitmap("path/to/icon.ico") # Windows
# or
window.iconphoto(False, tk.PhotoImage(file="path/to/icon.png"))
How do I create a tooltip?
class ToolTip:
def __init__(self, widget, text):
self.widget = widget
self.text = text
self.tooltip = None
self.widget.bind("<Enter>", self.show_tooltip)
self.widget.bind("<Leave>", self.hide_tooltip)
def show_tooltip(self, event=None):
x, y, _, _ = self.widget.bbox("insert")
x += self.widget.winfo_rootx() + 25
y += self.widget.winfo_rooty() + 25
self.tooltip = tk.Toplevel(self.widget)
self.tooltip.wm_overrideredirect(True)
self.tooltip.wm_geometry(f"+{x}+{y}")
label = tk.Label(
self.tooltip,
text=self.text,
background="yellow",
relief="solid",
borderwidth=1
)
label.pack()
def hide_tooltip(self, event=None):
if self.tooltip:
self.tooltip.destroy()
self.tooltip = None
# Usage
button = tk.Button(root, text="Button with tooltip")
ToolTip(button, "This is a tooltip")
Performance Optimization
Performance Tips
- Use
after()instead oftime.sleep():
def update_progress():
# Update UI
progress_bar['value'] += 1
if progress_bar['value'] < 100:
root.after(100, update_progress) # instead of time.sleep(0.1)
- Group configuration updates:
# Inefficient
widget.config(text="New text")
widget.config(bg="red")
widget.config(font=("Arial", 12))
# Efficient
widget.config(text="New text", bg="red", font=("Arial", 12))
- Use
StringVarfor frequent updates:
text_var = tk.StringVar()
label = tk.Label(root, textvariable=text_var)
# Fast update without recreating the widget
text_var.set("New text")
Debugging and Testing
Key Debugging Techniques
# Get widget info
print(widget.winfo_class()) # widget class
print(widget.winfo_geometry()) # size and position
print(widget.winfo_children()) # child widgets
print(widget.config()) # all configuration options
# Event tracing
def debug_event(event):
print(f"Event: {event.type}, Widget: {event.widget}")
root.bind_all("<Key>", debug_event)
Integration with Other Libraries
Using Matplotlib
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
def create_plot():
fig, ax = plt.subplots(figsize=(8, 6))
x = np.linspace(0, 10, 100)
y = np.sin(x)
ax.plot(x, y)
ax.set_title("Plot of sin(x)")
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
root = tk.Tk()
root.title("Matplotlib in Tkinter")
create_plot()
root.mainloop()
Working with Databases
import sqlite3
from tkinter import ttk
class DatabaseApp:
def __init__(self):
self.root = tk.Tk()
self.root.title("User Database")
# Create database
self.conn = sqlite3.connect("users.db")
self.create_table()
self.create_widgets()
def create_table(self):
cursor = self.conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL,
age INTEGER
)
""")
self.conn.commit()
def create_widgets(self):
# Input form
input_frame = tk.Frame(self.root)
input_frame.pack(pady=10)
tk.Label(input_frame, text="Name:").grid(row=0, column=0, padx=5)
self.name_entry = tk.Entry(input_frame)
self.name_entry.grid(row=0, column=1, padx=5)
tk.Label(input_frame, text="Email:").grid(row=1, column=0, padx=5)
self.email_entry = tk.Entry(input_frame)
self.email_entry.grid(row=1, column=1, padx=5)
tk.Label(input_frame, text="Age:").grid(row=2, column=0, padx=5)
self.age_entry = tk.Entry(input_frame)
self.age_entry.grid(row=2, column=1, padx=5)
# Buttons
button_frame = tk.Frame(self.root)
button_frame.pack(pady=10)
tk.Button(button_frame, text="Add", command=self.add_user).pack(side=tk.LEFT, padx=5)
tk.Button(button_frame, text="Refresh", command=self.refresh_list).pack(side=tk.LEFT, padx=5)
tk.Button(button_frame, text="Delete", command=self.delete_user).pack(side=tk.LEFT, padx=5)
# User table
self.tree = ttk.Treeview(self.root, columns=("ID", "Name", "Email", "Age"), show="headings")
self.tree.heading("ID", text="ID")
self.tree.heading("Name", text="Name")
self.tree.heading("Email", text="Email")
self.tree.heading("Age", text="Age")
self.tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
self.refresh_list()
def add_user(self):
name = self.name_entry.get()
email = self.email_entry.get()
age = self.age_entry.get()
if name and email and age:
cursor = self.conn.cursor()
cursor.execute("INSERT INTO users (name, email, age) VALUES (?, ?, ?)", (name, email, int(age)))
self.conn.commit()
# Clear fields
self.name_entry.delete(0, tk.END)
self.email_entry.delete(0, tk.END)
self.age_entry.delete(0, tk.END)
self.refresh_list()
def refresh_list(self):
# Clear table
for item in self.tree.get_children():
self.tree.delete(item)
# Load data
cursor = self.conn.cursor()
cursor.execute("SELECT * FROM users")
for row in cursor.fetchall():
self.tree.insert("", tk.END, values=row)
def delete_user(self):
selection = self.tree.selection()
if selection:
item = self.tree.item(selection[0])
user_id = item['values'][0]
cursor = self.conn.cursor()
cursor.execute("DELETE FROM users WHERE id = ?", (user_id,))
self.conn.commit()
self.refresh_list()
def run(self):
self.root.mainloop()
self.conn.close()
if __name__ == "__main__":
app = DatabaseApp()
app.run()
Deploying Applications
Creating an Executable with PyInstaller
# Install PyInstaller
pip install pyinstaller
# Build a one‑file executable
pyinstaller --onefile --windowed your_app.py
# With an icon
pyinstaller --onefile --windowed --icon=icon.ico your_app.py
# Include additional data files
pyinstaller --onefile --windowed --add-data "data;data" your_app.py
Project Structure for Distribution
my_tkinter_app/
├── main.py
├── requirements.txt
├── resources/
│ ├── icons/
│ └── images/
├── modules/
│ ├── __init__.py
│ ├── gui.py
│ └── logic.py
└── dist/
└── (executable files)
Pros and Cons of Tkinter
Advantages
Easy to learn: Tkinter offers an intuitive API and extensive documentation, making it ideal for newcomers.
Built‑in: Comes with Python by default, requiring no extra dependencies.
Cross‑platform: Applications run unchanged on Windows, macOS and Linux.
Stable: Over 30 years of development have resulted in a very stable API.
Lightweight: Low system requirements and fast startup.
Integrates well: Works smoothly with other Python libraries.
Disadvantages
Limited visual capabilities: Provides a basic widget set without modern styling.
Outdated look: By default, apps may appear dated compared to newer GUI frameworks.
Restricted customization: Complex custom UI elements are hard to implement.
Performance constraints: Not suited for high‑intensity graphics or heavy‑load apps.
No mobile support: Cannot create native mobile applications.
Alternatives to Tkinter
PyQt / PySide
A more powerful and modern framework with rich features, but it requires separate installation and has a steeper learning curve.
Kivy
Specializes in multitouch applications and supports mobile platforms.
wxPython
Provides native look‑and‑feel on each platform.
Dear PyGui
A contemporary library offering high performance for tools and utilities.
Conclusion
Tkinter remains one of the most accessible and practical tools for building graphical interfaces in Python. Despite its limitations, the library is perfect for learning GUI programming, creating internal tools, automation utilities, and rapid prototyping.
Its simplicity, lack of external dependencies, and extensive documentation make Tkinter a top choice for beginner developers and projects where development speed matters more than cutting‑edge UI design.
For serious commercial applications that demand a modern look, consider more advanced alternatives, but Tkinter will always be a reliable component in a Python developer’s toolbox for a wide range of desktop‑application tasks.
The Future of AI in Mathematics and Everyday Life: How Intelligent Agents Are Already Changing the Game
Experts warned about the risks of fake charity with AI
In Russia, universal AI-agent for robots and industrial processes was developed