Python’s tkinter module wraps the Tk GUI toolkit — create windows, buttons, text inputs, menus, and canvas drawings with zero extra dependencies. import tkinter as tk. Root window: root = tk.Tk(); root.title("App"); root.geometry("400x300"). Widgets: tk.Label(root, text="Name:"), tk.Button(root, text="OK", command=fn), tk.Entry(root) (single-line), tk.Text(root, height=10) (multi-line). Layout: .pack() (flow), .grid(row=0, column=1) (table), .place(x=50, y=50) (absolute). Get/set values: entry.get(), entry.delete(0, "end"), entry.insert(0, "text"); StringVar links a variable to a widget — var = tk.StringVar(); tk.Entry(root, textvariable=var). Events: widget.bind("<Button-1>", handler); <Return>, <KeyRelease>. Themed widgets: from tkinter import ttk — ttk.Combobox, ttk.Treeview, ttk.Notebook. Dialogs: tkinter.messagebox.showinfo("Title","msg"), tkinter.filedialog.askopenfilename(). Start loop: root.mainloop(). Claude Code generates form applications, data entry tools, file browsers, image viewers, and admin dashboards.
CLAUDE.md for tkinter
## tkinter Stack
- Stdlib: import tkinter as tk; from tkinter import ttk, messagebox, filedialog
- Root: root = tk.Tk(); root.title("App"); root.geometry("800x600")
- Widget: lbl = tk.Label(root, text="Hi"); lbl.pack()
- btn = tk.Button(root, text="OK", command=fn); btn.grid(row=0, col=1)
- ent = tk.Entry(root); var = tk.StringVar(); ent.config(textvariable=var)
- Event: widget.bind("<Return>", lambda e: fn())
- Dialog: messagebox.askyesno("?","Confirm?"); filedialog.askopenfilename()
- Loop: root.mainloop()
tkinter GUI Pipeline
# app/tkutil.py — form builder, widget helpers, tree view, canvas, dialogs
from __future__ import annotations
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog, ttk
from dataclasses import dataclass, field
from typing import Any, Callable
# ─────────────────────────────────────────────────────────────────────────────
# 1. Window and widget factories
# ─────────────────────────────────────────────────────────────────────────────
def make_root(
title: str = "App",
geometry: str = "600x400",
resizable: bool = True,
bg: str = "#f0f0f0",
) -> tk.Tk:
"""
Create and configure the root Tk window.
Example:
root = make_root("My App", "800x600")
root.mainloop()
"""
root = tk.Tk()
root.title(title)
root.geometry(geometry)
root.configure(bg=bg)
root.resizable(resizable, resizable)
return root
def labeled_entry(
parent: tk.Widget,
label: str,
default: str = "",
row: int = 0,
label_width: int = 12,
) -> tk.StringVar:
"""
Create a Label+Entry pair using grid layout and return the StringVar.
Example:
frame = tk.Frame(root)
name_var = labeled_entry(frame, "Name:", row=0)
email_var = labeled_entry(frame, "Email:", row=1)
"""
tk.Label(parent, text=label, width=label_width, anchor="w").grid(
row=row, column=0, sticky="w", padx=4, pady=2
)
var = tk.StringVar(value=default)
tk.Entry(parent, textvariable=var, width=30).grid(
row=row, column=1, sticky="ew", padx=4, pady=2
)
return var
def scrolled_text(
parent: tk.Widget,
width: int = 60,
height: int = 10,
) -> tk.Text:
"""
Create a Text widget with a vertical Scrollbar.
Example:
txt = scrolled_text(frame, height=15)
txt.insert("end", "Hello\n")
content = txt.get("1.0", "end-1c")
"""
frame = tk.Frame(parent)
frame.pack(fill="both", expand=True)
sb = tk.Scrollbar(frame)
sb.pack(side="right", fill="y")
txt = tk.Text(frame, width=width, height=height, yscrollcommand=sb.set, wrap="word")
txt.pack(side="left", fill="both", expand=True)
sb.config(command=txt.yview)
return txt
def scrolled_listbox(
parent: tk.Widget,
items: "list[str] | None" = None,
height: int = 8,
selectmode: str = "browse",
) -> tk.Listbox:
"""
Create a Listbox with a vertical Scrollbar and optional initial items.
Example:
lb = scrolled_listbox(frame, items=["Alice", "Bob", "Carol"])
selected = lb.get(lb.curselection()[0])
"""
frame = tk.Frame(parent)
frame.pack(fill="both", expand=True, padx=4, pady=4)
sb = tk.Scrollbar(frame)
sb.pack(side="right", fill="y")
lb = tk.Listbox(frame, yscrollcommand=sb.set, selectmode=selectmode, height=height)
lb.pack(side="left", fill="both", expand=True)
sb.config(command=lb.yview)
if items:
for item in items:
lb.insert("end", item)
return lb
# ─────────────────────────────────────────────────────────────────────────────
# 2. Form builder
# ─────────────────────────────────────────────────────────────────────────────
@dataclass
class FormField:
"""Definition of one field in a FormBuilder."""
name: str
label: str
default: str = ""
kind: str = "entry" # "entry", "combo", "check"
choices: list[str] = field(default_factory=list)
class FormBuilder:
"""
Build a simple grid-layout form from a list of FormField definitions.
Example:
fields = [
FormField("name", "Full Name:", default=""),
FormField("email", "Email:", default=""),
FormField("role", "Role:", kind="combo",
choices=["Admin", "User", "Guest"]),
FormField("active", "Active:", kind="check"),
]
form = FormBuilder(frame, fields)
def on_submit():
data = form.get_values()
print(data)
form.add_buttons(on_submit=on_submit)
"""
def __init__(self, parent: tk.Widget, fields: list[FormField]) -> None:
self._frame = tk.Frame(parent)
self._frame.pack(fill="both", expand=True, padx=8, pady=8)
self._vars: dict[str, Any] = {}
for row, f in enumerate(fields):
tk.Label(self._frame, text=f.label, width=14, anchor="w").grid(
row=row, column=0, sticky="w", padx=4, pady=3
)
if f.kind == "entry":
var = tk.StringVar(value=f.default)
tk.Entry(self._frame, textvariable=var, width=28).grid(
row=row, column=1, sticky="ew", padx=4
)
self._vars[f.name] = var
elif f.kind == "combo":
var2 = tk.StringVar(value=f.default or (f.choices[0] if f.choices else ""))
cb = ttk.Combobox(self._frame, textvariable=var2, values=f.choices, state="readonly")
cb.grid(row=row, column=1, sticky="ew", padx=4)
self._vars[f.name] = var2
elif f.kind == "check":
var3 = tk.BooleanVar(value=bool(f.default))
tk.Checkbutton(self._frame, variable=var3).grid(row=row, column=1, sticky="w", padx=4)
self._vars[f.name] = var3
self._frame.columnconfigure(1, weight=1)
self._btn_frame: "tk.Frame | None" = None
def add_buttons(
self,
on_submit: "Callable | None" = None,
on_cancel: "Callable | None" = None,
submit_label: str = "Submit",
cancel_label: str = "Cancel",
) -> None:
self._btn_frame = tk.Frame(self._frame)
self._btn_frame.grid(
row=100, column=0, columnspan=2, sticky="e", pady=8
)
if on_cancel:
tk.Button(self._btn_frame, text=cancel_label, command=on_cancel,
width=10).pack(side="right", padx=4)
if on_submit:
tk.Button(self._btn_frame, text=submit_label, command=on_submit,
width=10).pack(side="right", padx=4)
def get_values(self) -> dict[str, Any]:
return {name: var.get() for name, var in self._vars.items()}
def set_values(self, data: dict[str, Any]) -> None:
for name, value in data.items():
if name in self._vars:
self._vars[name].set(value)
# ─────────────────────────────────────────────────────────────────────────────
# 3. ttk Treeview table helper
# ─────────────────────────────────────────────────────────────────────────────
def make_table(
parent: tk.Widget,
columns: list[str],
col_widths: "list[int] | None" = None,
height: int = 15,
selectmode: str = "browse",
) -> ttk.Treeview:
"""
Create a ttk.Treeview with columns, headings, and a vertical scrollbar.
Example:
tree = make_table(frame, columns=["Name","Age","City"], col_widths=[150,60,100])
tree.insert("", "end", values=("Alice", 30, "London"))
tree.bind("<<TreeviewSelect>>", on_select)
"""
frame = tk.Frame(parent)
frame.pack(fill="both", expand=True, padx=4, pady=4)
sb = ttk.Scrollbar(frame, orient="vertical")
sb.pack(side="right", fill="y")
tree = ttk.Treeview(frame, columns=columns, show="headings",
height=height, selectmode=selectmode,
yscrollcommand=sb.set)
tree.pack(side="left", fill="both", expand=True)
sb.config(command=tree.yview)
widths = col_widths or [120] * len(columns)
for col, width in zip(columns, widths):
tree.heading(col, text=col)
tree.column(col, width=width, anchor="w")
return tree
def populate_table(tree: ttk.Treeview, rows: "list[tuple | list]") -> None:
"""
Clear the tree and insert rows.
Example:
populate_table(tree, [("Alice",30,"London"), ("Bob",25,"Paris")])
"""
for item in tree.get_children():
tree.delete(item)
for row in rows:
tree.insert("", "end", values=row)
# ─────────────────────────────────────────────────────────────────────────────
# 4. Status bar
# ─────────────────────────────────────────────────────────────────────────────
class StatusBar:
"""
A simple label-based status bar anchored to the bottom of a window.
Example:
sb = StatusBar(root)
sb.set("Ready")
sb.set("Loading...", temporary_ms=2000) # auto-clear after 2s
"""
def __init__(self, parent: tk.Widget) -> None:
self._var = tk.StringVar(value="Ready")
self._label = tk.Label(
parent, textvariable=self._var, bd=1, relief="sunken", anchor="w"
)
self._label.pack(side="bottom", fill="x")
self._after_id: "str | None" = None
def set(self, message: str, temporary_ms: int = 0) -> None:
if self._after_id:
self._label.after_cancel(self._after_id)
self._after_id = None
self._var.set(message)
if temporary_ms > 0:
self._after_id = self._label.after(temporary_ms, lambda: self._var.set("Ready"))
# ─────────────────────────────────────────────────────────────────────────────
# Demo application
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
import os
if not os.environ.get("DISPLAY") and os.name != "nt":
print("No display — skipping tkinter demo")
else:
root = make_root("tkinter Demo", "700x500")
# Menu bar
menu = tk.Menu(root)
file_menu = tk.Menu(menu, tearoff=0)
file_menu.add_command(label="Open...", command=lambda: filedialog.askopenfilename())
file_menu.add_separator()
file_menu.add_command(label="Exit", command=root.destroy)
menu.add_cascade(label="File", menu=file_menu)
root.config(menu=menu)
# Notebook (tabs)
nb = ttk.Notebook(root)
nb.pack(fill="both", expand=True, padx=8, pady=8)
# Tab 1: Form
tab1 = tk.Frame(nb)
nb.add(tab1, text="Form")
fields = [
FormField("name", "Name:", default="Alice"),
FormField("email", "Email:", default="[email protected]"),
FormField("role", "Role:", kind="combo",
choices=["Admin", "User", "Guest"]),
FormField("active","Active:", kind="check", default="1"),
]
form = FormBuilder(tab1, fields)
output_var = tk.StringVar()
def on_submit():
data = form.get_values()
output_var.set(str(data))
messagebox.showinfo("Submitted", f"Values: {data}")
form.add_buttons(on_submit=on_submit, on_cancel=lambda: form.set_values({}))
tk.Label(tab1, textvariable=output_var, wraplength=500, justify="left").pack(pady=4)
# Tab 2: Table
tab2 = tk.Frame(nb)
nb.add(tab2, text="Table")
tree = make_table(tab2, ["Name", "Score", "City"], col_widths=[140, 60, 120])
populate_table(tree, [
("Alice", 98, "London"),
("Bob", 72, "Paris"),
("Carol", 85, "Berlin"),
("David", 91, "Tokyo"),
])
# Tab 3: Text
tab3 = tk.Frame(nb)
nb.add(tab3, text="Text")
txt = scrolled_text(tab3, height=12)
txt.insert("end", "Type here...\nMultiple lines supported.\n")
# Status bar
sb = StatusBar(root)
sb.set("tkinter demo running")
root.mainloop()
For the PySimpleGUI / DearPyGui (PyPI) alternative — PySimpleGUI wraps tkinter (and optionally wx/Qt) behind a simpler list-of-lists layout API that eliminates callbacks and class boilerplate; DearPyGui uses a retained-mode GPU-accelerated renderer for high-performance dashboards — use PySimpleGUI for quick admin tools and prototypes where tkinter’s verbosity is a burden; use DearPyGui for real-time data displays; use tkinter when you need zero third-party dependencies and full control over the widget tree. For the PyQt6 / PySide6 (PyPI) alternative — Qt provides hundreds of widgets, model/view architecture, QSS styling, and a rich ecosystem (pyqtgraph, Qt Designer, etc.) — use Qt for production desktop applications that need icons, drag-and-drop, multi-document interfaces, and cross-platform theming; use tkinter for lightweight tools and when shipping a self-contained stdlib-only application. The Claude Skills 360 bundle includes tkinter skill sets covering make_root()/labeled_entry()/scrolled_text()/scrolled_listbox() factories, FormField/FormBuilder with get_values()/set_values(), make_table()/populate_table() ttk.Treeview helpers, and StatusBar with auto-clear messages. Start with the free tier to try tkinter patterns and GUI pipeline code generation.