Tkinter
GUI toolkit included in Python standard library. Based on Tcl/Tk, immediately usable without additional installation. Optimal for simple applications and prototyping with low learning cost.
Framework
Tkinter
Overview
Tkinter is a lightweight GUI framework included in Python's standard library. No additional installation required, enabling simple desktop application development. Ideal for learning, prototyping, and lightweight tool development, widely used as an introduction to desktop app development for Python programmers.
Details
Tkinter holds a solid position as the "first choice" for Python desktop development in 2025. As part of Python's standard library for over 20 years, it has advantages in stability and compatibility over other GUI frameworks.
The key feature is no additional installation required. GUI application development is immediately possible with just Python installed, making it the most accessible GUI framework for beginners. Based on Tcl/Tk, it's lightweight, memory-efficient, and provides sufficient functionality for simple applications.
Widely adopted in education, prototype development, internal tools, data analysis GUIs, and configuration screens. Tkinter is used in IDLE editor, pip-GUI, and many Python learning material sample applications, serving as the foundation for Python developers' desktop application development.
Pros and Cons
Pros
- Standard Library: Available immediately without additional installation
- Lightweight: Minimal resource consumption for simple GUI creation
- Low Learning Curve: Few concepts needed for basic GUI creation
- Stability: Over 20 years of proven track record and high compatibility
- Cross-platform: Windows, macOS, Linux support
- Rich Information: Numerous tutorials and learning resources
- Prototyping: Suitable for rapid UI prototyping
- No Dependencies: Development environment complete with Python only
Cons
- Appearance Limitations: Not suitable for modern UI design
- Limited Widgets: Only basic components, few advanced widgets
- Customization: Limited appearance customization options
- Responsiveness: Not suitable for complex layouts
- Animation: Difficult to implement dynamic UI effects
- Scalability: Not suitable for large-scale applications
Key Links
- Tkinter Official Documentation
- Tkinter Official Tutorial
- Tk/Tcl Official Site
- tkdocs.com (Modern Tkinter Learning)
- Tkinter 8.5 Reference
- Real Python Tkinter Guide
Code Examples
Hello World Application
# hello_world.py
import tkinter as tk
from tkinter import ttk
class HelloWorldApp:
def __init__(self, root):
self.root = root
self.root.title("Tkinter Hello World")
self.root.geometry("300x150")
# Main frame
self.main_frame = ttk.Frame(root, padding="10")
self.main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# Label
self.label = ttk.Label(self.main_frame, text="Hello, Tkinter!")
self.label.grid(row=0, column=0, columnspan=2, pady=10)
# Button
self.button = ttk.Button(
self.main_frame,
text="Click me",
command=self.on_button_click
)
self.button.grid(row=1, column=0, columnspan=2, pady=5)
# Counter display
self.counter_label = ttk.Label(self.main_frame, text="Click count: 0")
self.counter_label.grid(row=2, column=0, columnspan=2, pady=5)
# Window resize settings
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
self.main_frame.columnconfigure(0, weight=1)
self.click_count = 0
def on_button_click(self):
self.click_count += 1
self.counter_label.config(text=f"Click count: {self.click_count}")
if self.click_count == 1:
self.label.config(text="Button clicked!")
else:
self.label.config(text=f"Clicked {self.click_count} times!")
if __name__ == "__main__":
root = tk.Tk()
app = HelloWorldApp(root)
root.mainloop()
Basic Widget Usage
# basic_widgets.py
import tkinter as tk
from tkinter import ttk, messagebox
class BasicWidgetsApp:
def __init__(self, root):
self.root = root
self.root.title("Basic Widgets Example")
self.root.geometry("400x500")
# Scrollable frame
self.setup_scrollable_frame()
self.create_widgets()
def setup_scrollable_frame(self):
# Frame with scrollbar
self.canvas = tk.Canvas(self.root)
self.scrollbar = ttk.Scrollbar(self.root, orient="vertical", command=self.canvas.yview)
self.scrollable_frame = ttk.Frame(self.canvas)
self.scrollable_frame.bind(
"<Configure>",
lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
)
self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
self.canvas.configure(yscrollcommand=self.scrollbar.set)
self.canvas.pack(side="left", fill="both", expand=True)
self.scrollbar.pack(side="right", fill="y")
def create_widgets(self):
# Title
title = ttk.Label(self.scrollable_frame, text="Basic Widget Collection", font=("Arial", 16, "bold"))
title.pack(pady=10)
# Input fields
self.create_entry_section()
# Buttons
self.create_button_section()
# Checkboxes and radio buttons
self.create_checkbox_radio_section()
# Listbox and combobox
self.create_listbox_combobox_section()
# Scale and progress bar
self.create_scale_progress_section()
# Text area
self.create_text_section()
def create_entry_section(self):
# Entry fields
entry_frame = ttk.LabelFrame(self.scrollable_frame, text="Text Input", padding=10)
entry_frame.pack(fill="x", padx=10, pady=5)
ttk.Label(entry_frame, text="Name:").grid(row=0, column=0, sticky="w")
self.name_entry = ttk.Entry(entry_frame, width=30)
self.name_entry.grid(row=0, column=1, padx=5, pady=2)
ttk.Label(entry_frame, text="Password:").grid(row=1, column=0, sticky="w")
self.password_entry = ttk.Entry(entry_frame, show="*", width=30)
self.password_entry.grid(row=1, column=1, padx=5, pady=2)
# Show entry content button
ttk.Button(
entry_frame,
text="Show Content",
command=self.show_entry_content
).grid(row=2, column=1, sticky="e", pady=5)
def create_button_section(self):
# Buttons
button_frame = ttk.LabelFrame(self.scrollable_frame, text="Buttons", padding=10)
button_frame.pack(fill="x", padx=10, pady=5)
button_row = ttk.Frame(button_frame)
button_row.pack(fill="x")
ttk.Button(button_row, text="Info", command=lambda: messagebox.showinfo("Info", "Information message")).pack(side="left", padx=2)
ttk.Button(button_row, text="Warning", command=lambda: messagebox.showwarning("Warning", "Warning message")).pack(side="left", padx=2)
ttk.Button(button_row, text="Error", command=lambda: messagebox.showerror("Error", "Error message")).pack(side="left", padx=2)
def create_checkbox_radio_section(self):
# Checkboxes and radio buttons
check_radio_frame = ttk.LabelFrame(self.scrollable_frame, text="Selection", padding=10)
check_radio_frame.pack(fill="x", padx=10, pady=5)
# Checkboxes
self.check_vars = {}
check_frame = ttk.Frame(check_radio_frame)
check_frame.pack(fill="x")
ttk.Label(check_frame, text="Favorite languages:").pack(anchor="w")
for lang in ["Python", "JavaScript", "Java", "C++"]:
var = tk.BooleanVar()
self.check_vars[lang] = var
ttk.Checkbutton(check_frame, text=lang, variable=var).pack(anchor="w")
# Radio buttons
radio_frame = ttk.Frame(check_radio_frame)
radio_frame.pack(fill="x", pady=(10, 0))
ttk.Label(radio_frame, text="Experience level:").pack(anchor="w")
self.radio_var = tk.StringVar(value="Beginner")
for level in ["Beginner", "Intermediate", "Advanced"]:
ttk.Radiobutton(radio_frame, text=level, variable=self.radio_var, value=level).pack(anchor="w")
# Show selection button
ttk.Button(
check_radio_frame,
text="Show Selection",
command=self.show_selection
).pack(pady=5)
def create_listbox_combobox_section(self):
# Listbox and combobox
list_combo_frame = ttk.LabelFrame(self.scrollable_frame, text="Lists and Combos", padding=10)
list_combo_frame.pack(fill="x", padx=10, pady=5)
list_frame = ttk.Frame(list_combo_frame)
list_frame.pack(fill="x")
# Listbox
ttk.Label(list_frame, text="City selection:").pack(anchor="w")
self.listbox = tk.Listbox(list_frame, height=4)
cities = ["Tokyo", "Osaka", "Nagoya", "Fukuoka", "Sapporo", "Sendai"]
for city in cities:
self.listbox.insert(tk.END, city)
self.listbox.pack(fill="x", pady=2)
# Combobox
ttk.Label(list_frame, text="Country selection:").pack(anchor="w", pady=(10, 0))
self.combobox = ttk.Combobox(list_frame, values=["Japan", "USA", "UK", "Germany", "France"])
self.combobox.pack(fill="x", pady=2)
self.combobox.set("Japan")
def create_scale_progress_section(self):
# Scale and progress bar
scale_progress_frame = ttk.LabelFrame(self.scrollable_frame, text="Scale and Progress", padding=10)
scale_progress_frame.pack(fill="x", padx=10, pady=5)
# Scale
ttk.Label(scale_progress_frame, text="Value setting:").pack(anchor="w")
self.scale_var = tk.DoubleVar()
self.scale = ttk.Scale(
scale_progress_frame,
from_=0,
to=100,
variable=self.scale_var,
command=self.on_scale_change
)
self.scale.pack(fill="x", pady=2)
self.scale_label = ttk.Label(scale_progress_frame, text="Value: 0")
self.scale_label.pack(anchor="w")
# Progress bar
ttk.Label(scale_progress_frame, text="Progress:").pack(anchor="w", pady=(10, 0))
self.progress = ttk.Progressbar(scale_progress_frame, mode='determinate')
self.progress.pack(fill="x", pady=2)
ttk.Button(
scale_progress_frame,
text="Start Progress",
command=self.start_progress
).pack(pady=5)
def create_text_section(self):
# Text area
text_frame = ttk.LabelFrame(self.scrollable_frame, text="Text Area", padding=10)
text_frame.pack(fill="x", padx=10, pady=5)
self.text_area = tk.Text(text_frame, height=5, wrap=tk.WORD)
text_scrollbar = ttk.Scrollbar(text_frame, orient="vertical", command=self.text_area.yview)
self.text_area.configure(yscrollcommand=text_scrollbar.set)
self.text_area.pack(side="left", fill="both", expand=True)
text_scrollbar.pack(side="right", fill="y")
self.text_area.insert("1.0", "Enter your text here...")
def show_entry_content(self):
name = self.name_entry.get()
password = self.password_entry.get()
messagebox.showinfo("Input Content", f"Name: {name}\nPassword: {'*' * len(password)}")
def show_selection(self):
# Checkbox selection
selected_langs = [lang for lang, var in self.check_vars.items() if var.get()]
langs_text = ", ".join(selected_langs) if selected_langs else "None"
# Radio button selection
level = self.radio_var.get()
messagebox.showinfo("Selection", f"Favorite languages: {langs_text}\nExperience level: {level}")
def on_scale_change(self, value):
self.scale_label.config(text=f"Value: {float(value):.1f}")
self.progress['value'] = float(value)
def start_progress(self):
# Progress bar animation
self.progress['value'] = 0
self.animate_progress()
def animate_progress(self):
current_value = self.progress['value']
if current_value < 100:
self.progress['value'] = current_value + 2
self.root.after(50, self.animate_progress)
if __name__ == "__main__":
root = tk.Tk()
app = BasicWidgetsApp(root)
root.mainloop()
Layout Management (Grid, Pack, Place)
# layout_examples.py
import tkinter as tk
from tkinter import ttk
class LayoutExamples:
def __init__(self, root):
self.root = root
self.root.title("Layout Management Examples")
self.root.geometry("600x400")
# Create notebook (tabs)
self.notebook = ttk.Notebook(root)
self.notebook.pack(fill="both", expand=True, padx=10, pady=10)
# Create tabs for each layout
self.create_grid_tab()
self.create_pack_tab()
self.create_place_tab()
def create_grid_tab(self):
# Grid layout tab
grid_frame = ttk.Frame(self.notebook)
self.notebook.add(grid_frame, text="Grid Layout")
# Calculator-like layout
ttk.Label(grid_frame, text="Grid Layout - Calculator Style", font=("Arial", 12, "bold")).grid(row=0, column=0, columnspan=4, pady=10)
# Display
self.display_var = tk.StringVar(value="0")
display = ttk.Entry(grid_frame, textvariable=self.display_var, font=("Arial", 14), justify="right", state="readonly")
display.grid(row=1, column=0, columnspan=4, sticky="ew", padx=5, pady=5)
# Button layout
buttons = [
['C', '±', '%', '÷'],
['7', '8', '9', '×'],
['4', '5', '6', '-'],
['1', '2', '3', '+'],
['0', '', '.', '=']
]
for row_idx, row in enumerate(buttons):
for col_idx, text in enumerate(row):
if text:
if text == '0':
btn = ttk.Button(grid_frame, text=text, command=lambda t=text: self.calculator_click(t))
btn.grid(row=row_idx+2, column=col_idx, columnspan=2, sticky="ew", padx=2, pady=2)
else:
btn = ttk.Button(grid_frame, text=text, command=lambda t=text: self.calculator_click(t))
btn.grid(row=row_idx+2, column=col_idx, sticky="ew", padx=2, pady=2)
# Grid weight configuration
for i in range(4):
grid_frame.columnconfigure(i, weight=1)
def create_pack_tab(self):
# Pack layout tab
pack_frame = ttk.Frame(self.notebook)
self.notebook.add(pack_frame, text="Pack Layout")
ttk.Label(pack_frame, text="Pack Layout - Toolbar Style", font=("Arial", 12, "bold")).pack(pady=10)
# Top toolbar
toolbar = ttk.Frame(pack_frame, relief="raised", borderwidth=1)
toolbar.pack(fill="x", padx=5, pady=2)
ttk.Button(toolbar, text="New").pack(side="left", padx=2)
ttk.Button(toolbar, text="Open").pack(side="left", padx=2)
ttk.Button(toolbar, text="Save").pack(side="left", padx=2)
ttk.Separator(toolbar, orient="vertical").pack(side="left", fill="y", padx=5)
ttk.Button(toolbar, text="Copy").pack(side="left", padx=2)
ttk.Button(toolbar, text="Paste").pack(side="left", padx=2)
# Main area
main_area = ttk.Frame(pack_frame)
main_area.pack(fill="both", expand=True, padx=5, pady=5)
# Left sidebar
sidebar = ttk.LabelFrame(main_area, text="Sidebar", width=150)
sidebar.pack(side="left", fill="y", padx=(0, 5))
sidebar.pack_propagate(False) # Fixed size
for i in range(5):
ttk.Button(sidebar, text=f"Menu {i+1}").pack(fill="x", padx=5, pady=2)
# Central content
content = ttk.LabelFrame(main_area, text="Content Area")
content.pack(side="left", fill="both", expand=True)
ttk.Label(content, text="Main content is displayed here", font=("Arial", 14)).pack(expand=True)
# Bottom status bar
statusbar = ttk.Frame(pack_frame, relief="sunken", borderwidth=1)
statusbar.pack(fill="x", side="bottom", padx=5, pady=2)
ttk.Label(statusbar, text="Status: Ready").pack(side="left", padx=5)
ttk.Label(statusbar, text="Line: 1, Col: 1").pack(side="right", padx=5)
def create_place_tab(self):
# Place layout tab
place_frame = ttk.Frame(self.notebook)
self.notebook.add(place_frame, text="Place Layout")
ttk.Label(place_frame, text="Place Layout - Absolute Positioning", font=("Arial", 12, "bold")).place(x=10, y=10)
# Relative positioning
ttk.Label(place_frame, text="Top Left", background="lightblue").place(relx=0.1, rely=0.2, relwidth=0.2, relheight=0.1)
ttk.Label(place_frame, text="Top Right", background="lightgreen").place(relx=0.7, rely=0.2, relwidth=0.2, relheight=0.1)
ttk.Label(place_frame, text="Center", background="lightyellow").place(relx=0.4, rely=0.5, relwidth=0.2, relheight=0.1, anchor="center")
ttk.Label(place_frame, text="Bottom Left", background="lightcoral").place(relx=0.1, rely=0.8, relwidth=0.2, relheight=0.1)
ttk.Label(place_frame, text="Bottom Right", background="lightpink").place(relx=0.7, rely=0.8, relwidth=0.2, relheight=0.1)
# Absolute positioning
ttk.Button(place_frame, text="Absolute Button 1").place(x=50, y=100, width=120, height=30)
ttk.Button(place_frame, text="Absolute Button 2").place(x=200, y=140, width=120, height=30)
# Overlapping example
canvas = tk.Canvas(place_frame, width=200, height=100, background="white")
canvas.place(x=350, y=250)
canvas.create_rectangle(10, 10, 90, 50, fill="red", tags="rect1")
canvas.create_rectangle(50, 30, 130, 70, fill="blue", tags="rect2")
canvas.create_text(100, 80, text="Overlapping", tags="text1")
def calculator_click(self, text):
current = self.display_var.get()
if text == 'C':
self.display_var.set("0")
elif text in "0123456789":
if current == "0":
self.display_var.set(text)
else:
self.display_var.set(current + text)
elif text == ".":
if "." not in current:
self.display_var.set(current + ".")
else:
# Operators (simple implementation)
self.display_var.set(current + " " + text + " ")
if __name__ == "__main__":
root = tk.Tk()
app = LayoutExamples(root)
root.mainloop()
File Operations and Dialogs
# file_operations.py
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import os
from pathlib import Path
class FileOperationsApp:
def __init__(self, root):
self.root = root
self.root.title("File Operations and Dialogs")
self.root.geometry("600x500")
self.current_file = None
self.setup_ui()
def setup_ui(self):
# Menu bar
self.create_menu()
# Toolbar
toolbar = ttk.Frame(self.root)
toolbar.pack(fill="x", padx=5, pady=2)
ttk.Button(toolbar, text="New", command=self.new_file).pack(side="left", padx=2)
ttk.Button(toolbar, text="Open", command=self.open_file).pack(side="left", padx=2)
ttk.Button(toolbar, text="Save", command=self.save_file).pack(side="left", padx=2)
ttk.Button(toolbar, text="Save As", command=self.save_as_file).pack(side="left", padx=2)
ttk.Separator(toolbar, orient="vertical").pack(side="left", fill="y", padx=5)
ttk.Button(toolbar, text="Select Folder", command=self.select_folder).pack(side="left", padx=2)
# Main area
main_frame = ttk.Frame(self.root)
main_frame.pack(fill="both", expand=True, padx=5, pady=5)
# File info display
info_frame = ttk.LabelFrame(main_frame, text="File Information", padding=5)
info_frame.pack(fill="x", pady=(0, 5))
self.file_info_label = ttk.Label(info_frame, text="File: New Document")
self.file_info_label.pack(anchor="w")
# Text editor
editor_frame = ttk.LabelFrame(main_frame, text="Text Editor", padding=5)
editor_frame.pack(fill="both", expand=True)
# Text widget and scrollbar
self.text_widget = tk.Text(editor_frame, wrap=tk.WORD, undo=True)
scrollbar = ttk.Scrollbar(editor_frame, orient="vertical", command=self.text_widget.yview)
self.text_widget.configure(yscrollcommand=scrollbar.set)
self.text_widget.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
# Text change event
self.text_widget.bind('<Modified>', self.on_text_modified)
# Status bar
self.status_var = tk.StringVar(value="Ready")
status_bar = ttk.Label(self.root, textvariable=self.status_var, relief="sunken", anchor="w")
status_bar.pack(fill="x", side="bottom", padx=5, pady=2)
def create_menu(self):
menubar = tk.Menu(self.root)
self.root.config(menu=menubar)
# File menu
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=file_menu)
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_separator()
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, accelerator="Ctrl+Shift+S")
file_menu.add_separator()
file_menu.add_command(label="Exit", command=self.root.quit)
# Edit menu
edit_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Edit", menu=edit_menu)
edit_menu.add_command(label="Undo", command=lambda: self.text_widget.edit_undo(), accelerator="Ctrl+Z")
edit_menu.add_command(label="Redo", command=lambda: self.text_widget.edit_redo(), accelerator="Ctrl+Y")
edit_menu.add_separator()
edit_menu.add_command(label="Select All", command=self.select_all, accelerator="Ctrl+A")
# Keyboard shortcuts
self.root.bind('<Control-n>', lambda e: self.new_file())
self.root.bind('<Control-o>', lambda e: self.open_file())
self.root.bind('<Control-s>', lambda e: self.save_file())
self.root.bind('<Control-S>', lambda e: self.save_as_file())
self.root.bind('<Control-a>', lambda e: self.select_all())
def new_file(self):
if self.check_unsaved_changes():
self.text_widget.delete(1.0, tk.END)
self.current_file = None
self.update_file_info()
self.status_var.set("Created new file")
def open_file(self):
if not self.check_unsaved_changes():
return
file_path = filedialog.askopenfilename(
title="Open File",
filetypes=[
("Text files", "*.txt"),
("Python files", "*.py"),
("All files", "*.*")
]
)
if file_path:
try:
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()
self.text_widget.delete(1.0, tk.END)
self.text_widget.insert(1.0, content)
self.current_file = file_path
self.update_file_info()
self.text_widget.edit_modified(False)
self.status_var.set(f"Opened file: {os.path.basename(file_path)}")
except UnicodeDecodeError:
try:
with open(file_path, 'r', encoding='shift_jis') as file:
content = file.read()
self.text_widget.delete(1.0, tk.END)
self.text_widget.insert(1.0, content)
self.current_file = file_path
self.update_file_info()
self.text_widget.edit_modified(False)
self.status_var.set(f"Opened file: {os.path.basename(file_path)}")
except Exception as e:
messagebox.showerror("Error", f"Could not open file:\n{str(e)}")
except Exception as e:
messagebox.showerror("Error", f"Could not open file:\n{str(e)}")
def save_file(self):
if self.current_file:
self.save_to_file(self.current_file)
else:
self.save_as_file()
def save_as_file(self):
file_path = filedialog.asksaveasfilename(
title="Save As",
defaultextension=".txt",
filetypes=[
("Text files", "*.txt"),
("Python files", "*.py"),
("All files", "*.*")
]
)
if file_path:
self.save_to_file(file_path)
self.current_file = file_path
self.update_file_info()
def save_to_file(self, file_path):
try:
content = self.text_widget.get(1.0, tk.END + "-1c") # Exclude last newline
with open(file_path, 'w', encoding='utf-8') as file:
file.write(content)
self.text_widget.edit_modified(False)
self.status_var.set(f"Saved: {os.path.basename(file_path)}")
except Exception as e:
messagebox.showerror("Error", f"Could not save file:\n{str(e)}")
def select_folder(self):
folder_path = filedialog.askdirectory(title="Select Folder")
if folder_path:
self.show_folder_contents(folder_path)
def show_folder_contents(self, folder_path):
# Show folder contents in new window
folder_window = tk.Toplevel(self.root)
folder_window.title(f"Folder Contents: {os.path.basename(folder_path)}")
folder_window.geometry("400x300")
# Listbox and scrollbar
frame = ttk.Frame(folder_window)
frame.pack(fill="both", expand=True, padx=10, pady=10)
listbox = tk.Listbox(frame)
scrollbar = ttk.Scrollbar(frame, orient="vertical", command=listbox.yview)
listbox.configure(yscrollcommand=scrollbar.set)
# Display files and folders
try:
items = os.listdir(folder_path)
for item in sorted(items):
item_path = os.path.join(folder_path, item)
if os.path.isdir(item_path):
listbox.insert(tk.END, f"📁 {item}")
else:
listbox.insert(tk.END, f"📄 {item}")
except Exception as e:
listbox.insert(tk.END, f"Error: {str(e)}")
listbox.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
# Double-click to open file
def on_double_click(event):
selection = listbox.curselection()
if selection:
item_name = listbox.get(selection[0])[2:] # Remove icon
item_path = os.path.join(folder_path, item_name)
if os.path.isfile(item_path):
folder_window.destroy()
self.open_specific_file(item_path)
listbox.bind('<Double-1>', on_double_click)
def open_specific_file(self, file_path):
if not self.check_unsaved_changes():
return
try:
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()
self.text_widget.delete(1.0, tk.END)
self.text_widget.insert(1.0, content)
self.current_file = file_path
self.update_file_info()
self.text_widget.edit_modified(False)
self.status_var.set(f"Opened file: {os.path.basename(file_path)}")
except Exception as e:
messagebox.showerror("Error", f"Could not open file:\n{str(e)}")
def check_unsaved_changes(self):
if self.text_widget.edit_modified():
result = messagebox.askyesnocancel(
"Unsaved Changes",
"File has unsaved changes. Save them?"
)
if result is True: # Yes
self.save_file()
return True
elif result is False: # No
return True
else: # Cancel
return False
return True
def update_file_info(self):
if self.current_file:
file_path = Path(self.current_file)
file_info = f"File: {file_path.name} ({file_path.parent})"
try:
stat = file_path.stat()
size = stat.st_size
mtime = stat.st_mtime
from datetime import datetime
mtime_str = datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M:%S")
file_info += f" | Size: {size} bytes | Modified: {mtime_str}"
except:
pass
else:
file_info = "File: New Document"
self.file_info_label.config(text=file_info)
def on_text_modified(self, event):
if self.text_widget.edit_modified():
title = self.root.title()
if not title.endswith(" *"):
self.root.title(title + " *")
else:
title = self.root.title()
if title.endswith(" *"):
self.root.title(title[:-2])
def select_all(self):
self.text_widget.tag_add(tk.SEL, "1.0", tk.END)
self.text_widget.mark_set(tk.INSERT, "1.0")
self.text_widget.see(tk.INSERT)
return "break"
if __name__ == "__main__":
root = tk.Tk()
app = FileOperationsApp(root)
root.mainloop()
Setup and Environment
# Tkinter is included in Python standard library - no additional installation needed
# Check Python environment
python -c "import tkinter; print('Tkinter available')"
# Check available themes (ttk.Style)
python -c "import tkinter as tk; from tkinter import ttk; root=tk.Tk(); print(ttk.Style().theme_names()); root.destroy()"
# Install Pillow if image processing is needed
pip install Pillow
# Run application
python hello_world.py
# Create standalone executable
pip install pyinstaller
pyinstaller --onefile --windowed hello_world.py
# Linux environment tkinter check
# Ubuntu/Debian
sudo apt-get install python3-tk
# CentOS/RHEL
sudo yum install tkinter
# or
sudo dnf install python3-tkinter
Example Project Structure
my_tkinter_app/
├── main.py # Main application
├── widgets/
│ ├── __init__.py
│ ├── custom_widgets.py # Custom widgets
│ └── dialogs.py # Custom dialogs
├── utils/
│ ├── __init__.py
│ ├── file_handler.py # File operations
│ └── config.py # Configuration management
├── resources/
│ ├── icons/ # Icon files
│ └── images/ # Image files
├── tests/
│ ├── __init__.py
│ └── test_widgets.py # Test files
├── requirements.txt
└── README.md