文章目录
-
- 目录
- 一、基础框架
- 二、常用控件
-
- [1. 标签 Label](#1. 标签 Label)
- [2. 按钮 Button](#2. 按钮 Button)
- [3. 单行输入框 Entry](#3. 单行输入框 Entry)
- [4. 多行文本框 Text](#4. 多行文本框 Text)
- [5. 复选框 Checkbutton](#5. 复选框 Checkbutton)
- [6. 单选框 Radiobutton](#6. 单选框 Radiobutton)
- [7. 列表框 Listbox](#7. 列表框 Listbox)
- [8. 下拉框 Combobox(ttk)](#8. 下拉框 Combobox(ttk))
- [9. 滑块 Scale](#9. 滑块 Scale)
- [10. 微调框 Spinbox](#10. 微调框 Spinbox)
- [11. 容器 Frame / LabelFrame](#11. 容器 Frame / LabelFrame)
- [12. 进度条 Progressbar(ttk)](#12. 进度条 Progressbar(ttk))
- 三、布局管理
- 四、事件绑定
- 五、对话框
- 六、菜单
- [七、Canvas 画布](#七、Canvas 画布)
- 八、完整综合示例
- 九、常见坑
- 十、总结
目录
一、基础框架
python
import tkinter as tk
from tkinter import ttk, messagebox, filedialog, colorchooser
root = tk.Tk()
root.title("标题")
root.geometry("900x600") # 宽x高
root.resizable(True, True)
root.mainloop()
变量类(配合控件双向绑定)
python
s = tk.StringVar(value="abc")
i = tk.IntVar(value=10)
d = tk.DoubleVar(value=1.5)
b = tk.BooleanVar(value=True)
s.get() # 读取
s.set("x") # 设置
二、常用控件
1. 标签 Label
python
tk.Label(root, text="文字", font=("微软雅黑", 12),
fg="blue", bg="white").pack()
2. 按钮 Button
python
def on_click():
print("点击了")
tk.Button(root, text="按钮", command=on_click,
width=10, height=2, bg="#ddd", fg="black",
state=tk.NORMAL).pack()
3. 单行输入框 Entry
python
var = tk.StringVar()
entry = tk.Entry(root, textvariable=var, width=20, show=None)
entry.pack()
# var.get() 读取
# var.set("x") 设置
# entry.delete(0, tk.END) 清空
show="*"可做密码框。
4. 多行文本框 Text
python
text = tk.Text(root, width=40, height=8, wrap=tk.WORD)
text.pack()
text.insert(tk.END, "第一行\n")
text.insert("1.0", "插入开头\n")
content = text.get("1.0", tk.END)
text.delete("1.0", tk.END)
5. 复选框 Checkbutton
python
v = tk.BooleanVar()
tk.Checkbutton(root, text="启用", variable=v).pack()
print(v.get()) # True / False
6. 单选框 Radiobutton
python
v = tk.StringVar(value="A")
tk.Radiobutton(root, text="选项A", variable=v, value="A").pack()
tk.Radiobutton(root, text="选项B", variable=v, value="B").pack()
7. 列表框 Listbox
python
lb = tk.Listbox(root, height=6, selectmode=tk.EXTENDED)
lb.pack()
lb.insert(tk.END, "item1", "item2")
sel = lb.curselection() # 选中索引元组
val = lb.get(sel[0]) if sel else None
lb.delete(0, tk.END) # 清空
lb.bind("<<ListboxSelect>>", lambda e: print("选中变化"))
8. 下拉框 Combobox(ttk)
python
var = tk.StringVar(value="矩形")
cb = ttk.Combobox(root, textvariable=var, state="readonly",
values=["矩形", "椭圆", "直线"])
cb.pack()
cb.current(0) # 选第 0 项
cb.bind("<<ComboboxSelected>>", lambda e: print(var.get()))
9. 滑块 Scale
python
v = tk.IntVar(value=5)
tk.Scale(root, from_=1, to=20, orient=tk.HORIZONTAL,
variable=v, length=200).pack()
10. 微调框 Spinbox
python
v = tk.IntVar(value=3)
tk.Spinbox(root, from_=1, to=100, textvariable=v, width=5).pack()
11. 容器 Frame / LabelFrame
python
f1 = tk.Frame(root, bd=1, relief=tk.GROOVE)
f1.pack(fill=tk.BOTH, expand=True)
f2 = tk.LabelFrame(root, text="设置")
f2.pack(fill=tk.X)
12. 进度条 Progressbar(ttk)
python
pb = ttk.Progressbar(root, maximum=100, mode="determinate")
pb.pack(fill=tk.X)
pb["value"] = 40 # 设置进度
pb.start(50) # 动画
pb.stop()
三、布局管理
pack:简单堆叠
python
w.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5, pady=5)
grid:表格
python
w.grid(row=0, column=1, sticky="nsew", padx=5, pady=5)
root.columnconfigure(1, weight=1)
root.rowconfigure(0, weight=1)
place:绝对定位
python
w.place(x=20, y=30, width=100, height=30)
⚠️ 同一个父容器里不要混用 pack 和 grid。
四、事件绑定
python
widget.bind("<Button-1>", handler) # 左键
widget.bind("<B1-Motion>", handler) # 左键拖动
widget.bind("<ButtonRelease-1>", handler) # 左键释放
widget.bind("<Motion>", handler) # 鼠标移动
widget.bind("<KeyPress>", handler) # 键盘按下
widget.bind("<Return>", handler) # 回车
widget.bind("<Configure>", handler) # 尺寸变化
after(ms, func)做定时任务,不要用time.sleep。
五、对话框
python
messagebox.showinfo("提示", "操作成功")
messagebox.showwarning("警告", "注意")
messagebox.showerror("错误", "出错了")
ok = messagebox.askyesno("确认", "确定删除吗?")
path = filedialog.askopenfilename(filetypes=[("文本", "*.txt")])
path = filedialog.asksaveasfilename(defaultextension=".txt")
color = colorchooser.askcolor()[1] # 返回 '#rrggbb'
六、菜单
顶部菜单栏
python
menubar = tk.Menu(root)
file_menu = tk.Menu(menubar, tearoff=0)
file_menu.add_command(label="新建", command=lambda: print("新建"))
file_menu.add_separator()
file_menu.add_command(label="退出", command=root.quit)
menubar.add_cascade(label="文件", menu=file_menu)
root.config(menu=menubar)
右键菜单
python
menu = tk.Menu(root, tearoff=0)
menu.add_command(label="复制")
menu.add_command(label="粘贴")
def popup(e):
menu.tk_popup(e.x_root, e.y_root)
widget.bind("<Button-3>", popup)
七、Canvas 画布
7.1 创建画布
python
canvas = tk.Canvas(
root,
width=700, height=500,
bg="white",
bd=2, relief=tk.SUNKEN,
highlightthickness=0,
scrollregion=(0, 0, 2000, 1500)
)
canvas.pack(fill=tk.BOTH, expand=True)
7.2 坐标系统
- 左上角为
(0, 0) x向右增大,y向下增大- 所有绘图方法返回一个 item id,用于后续修改、移动、删除
python
rect = canvas.create_rectangle(50, 50, 200, 150)
print(rect) # 例如 1
7.3 绘制图形
直线
python
line = canvas.create_line(
20, 20, 300, 200,
fill="red", width=3, dash=(5, 3),
arrow=tk.LAST, capstyle=tk.ROUND,
joinstyle=tk.ROUND, smooth=True,
tags="line"
)
| 选项 | 说明 |
|---|---|
fill |
颜色 |
width |
线宽 |
dash |
虚线,如 (5, 3) |
arrow |
tk.FIRST / tk.LAST / tk.BOTH |
capstyle |
线端样式 |
joinstyle |
拐角样式 |
smooth |
是否平滑曲线 |
tags |
标签 |
矩形
python
rect = canvas.create_rectangle(
50, 50, 250, 180,
fill="#aee", outline="blue",
width=2, dash=(4, 2), tags="rect"
)
椭圆 / 圆
python
oval = canvas.create_oval(
300, 50, 500, 200,
fill="#fea", outline="orange",
width=3, tags="oval"
)
# 画圆时宽高相等
canvas.create_oval(100, 100, 200, 200, fill="pink")
圆弧 / 扇形 / 弓形
python
arc = canvas.create_arc(
50, 250, 250, 450,
start=0, extent=120,
style=tk.PIESLICE,
fill="yellow", outline="black", width=2
)
| style 值 | 效果 |
|---|---|
tk.ARC |
只画弧线 |
tk.PIESLICE |
扇形 |
tk.CHORD |
弓形 |
多边形
python
poly = canvas.create_polygon(
300, 250, 450, 250, 500, 400, 250, 400,
fill="#cfc", outline="green", width=2,
smooth=True, tags="poly"
)
文本
python
text = canvas.create_text(
400, 500,
text="你好,Canvas",
font=("微软雅黑", 18, "bold"),
fill="black", anchor="center",
width=200, justify="left", tags="text"
)
anchor 可选:tk.N / tk.NE / tk.E / tk.SE / tk.S / tk.SW / tk.W / tk.NW / tk.CENTER
图片
python
photo = tk.PhotoImage(file="logo.png")
img = canvas.create_image(100, 100, image=photo, anchor="nw")
使用 Pillow:
python
from PIL import Image, ImageTk
pil_image = Image.open("photo.jpg").resize((200, 150))
photo = ImageTk.PhotoImage(pil_image)
canvas.create_image(100, 100, image=photo, anchor="nw")
⚠️
photo必须保存为全局变量或实例属性,否则会被垃圾回收导致图片不显示。
嵌入其他控件
python
entry = tk.Entry(root)
canvas.create_window(300, 300, window=entry,
anchor="nw", width=200, height=30)
7.4 图形项管理
python
rect = canvas.create_rectangle(50, 50, 150, 100,
fill="red", tags="myrect")
| 操作 | 代码 |
|---|---|
| 修改配置 | canvas.itemconfig(rect, fill="blue", width=3) |
| 获取配置 | canvas.itemcget(rect, "fill") |
| 修改坐标 | canvas.coords(rect, 100, 100, 250, 200) |
| 获取坐标 | canvas.coords(rect) |
| 移动 | canvas.move(rect, 10, 20) |
| 缩放 | canvas.scale(rect, 0, 0, 2, 2) |
| 删除单个 | canvas.delete(rect) |
| 按 tag 删除 | canvas.delete("myrect") |
| 删除全部 | canvas.delete("all") |
| 查找全部 | canvas.find_all() |
| 按 tag 查找 | canvas.find_withtag("myrect") |
| 就近查找 | canvas.find_closest(100, 100) |
| 重叠查找 | canvas.find_overlapping(0, 0, 200, 200) |
| 包围查找 | canvas.find_enclosed(0, 0, 200, 200) |
| 添加 tag | canvas.addtag_withtag("newtag", rect) |
| 获取 tag | canvas.gettags(rect) |
| 删除 tag | canvas.dtag(rect, "myrect") |
| 提升层级 | canvas.lift(rect) |
| 降低层级 | canvas.lower(rect) |
| 边界框 | canvas.bbox(rect) |
| 类型 | canvas.type(rect) |
7.5 事件绑定
整个 Canvas 绑定:
python
def on_click(event):
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)
print("点击画布坐标:", x, y)
canvas.bind("<Button-1>", on_click)
给某个图形绑定:
python
def click_rect(event):
print("点击了矩形")
canvas.tag_bind("myrect", "<Button-1>", click_rect)
拖动矩形示例:
python
rect = canvas.create_rectangle(100, 100, 200, 160,
fill="skyblue", tags="drag")
start_x = start_y = 0
def start_drag(event):
global start_x, start_y
start_x = canvas.canvasx(event.x)
start_y = canvas.canvasy(event.y)
canvas.lift("drag")
def drag(event):
global start_x, start_y
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)
canvas.move("drag", x - start_x, y - start_y)
start_x, start_y = x, y
canvas.tag_bind("drag", "<Button-1>", start_drag)
canvas.tag_bind("drag", "<B1-Motion>", drag)
7.6 滚动条
python
frame = tk.Frame(root)
frame.pack(fill=tk.BOTH, expand=True)
canvas = tk.Canvas(frame, bg="white",
scrollregion=(0, 0, 2000, 1500))
hbar = tk.Scrollbar(frame, orient=tk.HORIZONTAL, command=canvas.xview)
vbar = tk.Scrollbar(frame, orient=tk.VERTICAL, command=canvas.yview)
canvas.configure(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
hbar.pack(side=tk.BOTTOM, fill=tk.X)
vbar.pack(side=tk.RIGHT, fill=tk.Y)
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
内容动态增加时自动更新滚动区域:
python
canvas.configure(scrollregion=canvas.bbox("all"))
鼠标滚轮:
python
def on_mousewheel(event):
canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
canvas.bind_all("<MouseWheel>", on_mousewheel)
Linux 下:
python
canvas.bind_all("<Button-4>", lambda e: canvas.yview_scroll(-1, "units"))
canvas.bind_all("<Button-5>", lambda e: canvas.yview_scroll(1, "units"))
7.7 动画
python
ball = canvas.create_oval(20, 100, 70, 150, fill="red")
def animate():
canvas.move(ball, 3, 0)
x1, y1, x2, y2 = canvas.coords(ball)
if x2 > 700:
canvas.coords(ball, 20, 100, 70, 150)
root.after(16, animate) # 约 60 FPS
animate()
八、完整综合示例
一个绘图板程序,包含:菜单栏、工具栏(下拉框、输入框、按钮、滑块、复选框、颜色选择)、左侧列表、右侧 Canvas、底部状态栏。
python
import tkinter as tk
from tkinter import ttk, messagebox, filedialog, colorchooser
class DrawingApp:
def __init__(self, root):
self.root = root
root.title("Tkinter 综合示例 - 绘图板")
root.geometry("1100x700")
root.minsize(800, 500)
# ---------- 状态数据 ----------
self.fill_color = "#88ccff"
self.outline_color = "#0055aa"
self.items = {} # canvas item id -> 描述
self.list_order = [] # listbox 索引 -> item id
self.start = None # 拖动起点
self.temp = None # 正在绘制的临时图形
# ---------- 界面 ----------
self._build_menu()
self._build_toolbar()
self._build_body()
self._build_status()
self.canvas.bind_all("<MouseWheel>", self.on_wheel)
# ================= 菜单 =================
def _build_menu(self):
menubar = tk.Menu(self.root)
file_menu = tk.Menu(menubar, tearoff=0)
file_menu.add_command(label="导出为 PostScript",
command=self.export_ps)
file_menu.add_separator()
file_menu.add_command(label="退出", command=self.root.quit)
menubar.add_cascade(label="文件", menu=file_menu)
edit_menu = tk.Menu(menubar, tearoff=0)
edit_menu.add_command(label="清空画布", command=self.clear_all)
edit_menu.add_command(label="删除选中",
command=self.delete_selected)
menubar.add_cascade(label="编辑", menu=edit_menu)
help_menu = tk.Menu(menubar, tearoff=0)
help_menu.add_command(
label="关于",
command=lambda: messagebox.showinfo("关于", "Tkinter 综合示例")
)
menubar.add_cascade(label="帮助", menu=help_menu)
self.root.config(menu=menubar)
# ================= 顶部工具栏 =================
def _build_toolbar(self):
bar = tk.Frame(self.root, bd=1, relief=tk.RAISED)
bar.pack(side=tk.TOP, fill=tk.X)
# 图形类型
tk.Label(bar, text="图形:").pack(side=tk.LEFT, padx=(8, 2), pady=6)
self.shape_var = tk.StringVar(value="矩形")
ttk.Combobox(bar, textvariable=self.shape_var, state="readonly",
values=["矩形", "椭圆", "直线", "文本"], width=8
).pack(side=tk.LEFT)
# 填充色
tk.Button(bar, text="填充色", command=self.choose_fill
).pack(side=tk.LEFT, padx=(10, 4))
self.fill_preview = tk.Label(bar, bg=self.fill_color, width=3,
relief=tk.SUNKEN)
self.fill_preview.pack(side=tk.LEFT)
# 边框色
tk.Button(bar, text="边框色", command=self.choose_outline
).pack(side=tk.LEFT, padx=(10, 4))
self.outline_preview = tk.Label(bar, bg=self.outline_color, width=3,
relief=tk.SUNKEN)
self.outline_preview.pack(side=tk.LEFT)
# 线宽
tk.Label(bar, text="线宽:").pack(side=tk.LEFT, padx=(12, 2))
self.width_var = tk.IntVar(value=2)
tk.Scale(bar, from_=1, to=15, orient=tk.HORIZONTAL,
variable=self.width_var, length=110).pack(side=tk.LEFT)
# 是否填充
self.fill_on = tk.BooleanVar(value=True)
tk.Checkbutton(bar, text="填充", variable=self.fill_on
).pack(side=tk.LEFT, padx=8)
# 文本内容
tk.Label(bar, text="文本:").pack(side=tk.LEFT, padx=(8, 2))
self.text_var = tk.StringVar(value="Hello")
tk.Entry(bar, textvariable=self.text_var, width=12).pack(side=tk.LEFT)
# 清空按钮
tk.Button(bar, text="清空", command=self.clear_all
).pack(side=tk.LEFT, padx=(12, 4))
# ================= 主体区域 =================
def _build_body(self):
body = tk.Frame(self.root)
body.pack(fill=tk.BOTH, expand=True)
# ---------- 左侧面板 ----------
left = tk.Frame(body, width=210, bd=1, relief=tk.GROOVE)
left.pack(side=tk.LEFT, fill=tk.Y)
left.pack_propagate(False)
tk.Label(left, text="图形列表", font=("微软雅黑", 11, "bold")
).pack(pady=(10, 4))
lb_frame = tk.Frame(left)
lb_frame.pack(fill=tk.BOTH, expand=True, padx=8)
sb = tk.Scrollbar(lb_frame, orient=tk.VERTICAL)
self.listbox = tk.Listbox(lb_frame, yscrollcommand=sb.set)
sb.config(command=self.listbox.yview)
sb.pack(side=tk.RIGHT, fill=tk.Y)
self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.listbox.bind("<<ListboxSelect>>", self.on_select)
tk.Button(left, text="删除选中", command=self.delete_selected
).pack(fill=tk.X, padx=8, pady=(8, 4))
tk.Button(left, text="清空画布", command=self.clear_all
).pack(fill=tk.X, padx=8, pady=(0, 10))
# ---------- 右侧画布 ----------
right = tk.Frame(body)
right.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.canvas = tk.Canvas(right, bg="white", highlightthickness=0,
scrollregion=(0, 0, 2400, 1800))
hbar = tk.Scrollbar(right, orient=tk.HORIZONTAL,
command=self.canvas.xview)
vbar = tk.Scrollbar(right, orient=tk.VERTICAL,
command=self.canvas.yview)
self.canvas.configure(xscrollcommand=hbar.set,
yscrollcommand=vbar.set)
hbar.pack(side=tk.BOTTOM, fill=tk.X)
vbar.pack(side=tk.RIGHT, fill=tk.Y)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 画布事件
self.canvas.bind("<Button-1>", self.on_press)
self.canvas.bind("<B1-Motion>", self.on_drag)
self.canvas.bind("<ButtonRelease-1>", self.on_release)
self.canvas.bind("<Motion>", self.on_motion)
# ================= 状态栏 =================
def _build_status(self):
self.status = tk.StringVar(value="就绪:选择图形后在画布上拖动绘制")
tk.Label(self.root, textvariable=self.status, anchor=tk.W,
bd=1, relief=tk.SUNKEN, padx=6
).pack(side=tk.BOTTOM, fill=tk.X)
# ================= 颜色选择 =================
def choose_fill(self):
color = colorchooser.askcolor(color=self.fill_color)[1]
if color:
self.fill_color = color
self.fill_preview.config(bg=color)
def choose_outline(self):
color = colorchooser.askcolor(color=self.outline_color)[1]
if color:
self.outline_color = color
self.outline_preview.config(bg=color)
# ================= 画布事件 =================
def on_press(self, event):
x = self.canvas.canvasx(event.x)
y = self.canvas.canvasy(event.y)
self.start = (x, y)
shape = self.shape_var.get()
w = self.width_var.get()
fill = self.fill_color if self.fill_on.get() else ""
# 文本:单击直接创建
if shape == "文本":
item = self.canvas.create_text(
x, y, text=self.text_var.get(),
fill=self.outline_color, font=("微软雅黑", 16),
anchor="nw"
)
self.register(item, f"文本: {self.text_var.get()}")
self.start = None
return
# 其他:拖动创建
if shape == "直线":
self.temp = self.canvas.create_line(
x, y, x, y, fill=self.outline_color, width=w,
capstyle=tk.ROUND
)
elif shape == "矩形":
self.temp = self.canvas.create_rectangle(
x, y, x, y, fill=fill, outline=self.outline_color, width=w
)
elif shape == "椭圆":
self.temp = self.canvas.create_oval(
x, y, x, y, fill=fill, outline=self.outline_color, width=w
)
def on_drag(self, event):
if self.temp is None or self.start is None:
return
x = self.canvas.canvasx(event.x)
y = self.canvas.canvasy(event.y)
x0, y0 = self.start
self.canvas.coords(self.temp, x0, y0, x, y)
def on_release(self, event):
if self.temp is not None:
self.register(self.temp, self.shape_var.get())
self.temp = None
self.start = None
def on_motion(self, event):
x = self.canvas.canvasx(event.x)
y = self.canvas.canvasy(event.y)
self.status.set(f"坐标: x={int(x)}, y={int(y)}")
def on_wheel(self, event):
self.canvas.yview_scroll(int(-event.delta / 120), "units")
# ================= 列表管理 =================
def register(self, item, kind):
"""把新图形登记到列表"""
self.items[item] = kind
self.refresh_list()
def refresh_list(self):
self.listbox.delete(0, tk.END)
self.list_order = []
for item in self.canvas.find_all():
if item in self.items:
self.list_order.append(item)
self.listbox.insert(tk.END, f"[{item}] {self.items[item]}")
def on_select(self, event):
sel = self.listbox.curselection()
if not sel:
return
item = self.list_order[sel[0]]
self.status.set(f"选中: {self.items.get(item, '')} (id={item})")
def delete_selected(self):
sel = self.listbox.curselection()
if not sel:
messagebox.showinfo("提示", "请先在左侧列表中选择要删除的图形")
return
for i in reversed(sel):
item = self.list_order[i]
self.canvas.delete(item)
self.items.pop(item, None)
self.refresh_list()
self.status.set("已删除选中图形")
def clear_all(self):
self.canvas.delete("all")
self.items.clear()
self.refresh_list()
self.status.set("画布已清空")
# ================= 导出 =================
def export_ps(self):
path = filedialog.asksaveasfilename(
defaultextension=".ps",
filetypes=[("PostScript 文件", "*.ps")]
)
if not path:
return
try:
self.canvas.postscript(file=path, colormode="color")
messagebox.showinfo("完成", f"已导出到:\n{path}")
except Exception as e:
messagebox.showerror("导出失败", str(e))
if __name__ == "__main__":
root = tk.Tk()
app = DrawingApp(root)
root.mainloop()
使用说明
| 操作 | 效果 |
|---|---|
| 顶部下拉框选图形 | 矩形 / 椭圆 / 直线 / 文本 |
| 点"填充色 / 边框色" | 打开颜色选择器 |
| 拖动"线宽"滑块 | 调节线条宽度 |
| 勾选"填充" | 矩形/椭圆是否填充颜色 |
| "文本"框输入内容 | 选择"文本"图形后单击画布即可放置 |
| 在画布上按住拖动 | 绘制当前图形 |
| 鼠标滚轮 | 垂直滚动画布 |
| 左侧列表 | 显示所有图形,点击查看信息 |
| "删除选中" / "清空画布" | 删除图形 |
| 菜单"文件 → 导出" | 导出为 PostScript |
| 底部状态栏 | 实时显示鼠标坐标与操作提示 |
九、常见坑
-
图片不显示
PhotoImage或ImageTk.PhotoImage必须保持引用,否则会被垃圾回收。 -
滚动后坐标不对
事件中的
event.x、event.y是窗口坐标,滚动后应使用:pythonx = canvas.canvasx(event.x) y = canvas.canvasy(event.y) -
删除图形后 id 失效
删除后不要再使用旧 id。
-
动画不要用
time.sleep使用
root.after()。 -
Canvas 不是位图画布
它是矢量图形项集合,适合画线、图形、文本、嵌入控件;如果要像素级绘图,用 Pillow +
create_image。 -
scrollregion要设置正确否则滚动条范围不对。可动态设置:
pythoncanvas.configure(scrollregion=canvas.bbox("all")) -
pack和grid不要混用同一个父容器里不要同时使用两种布局管理器。
-
ttk.Combobox用state="readonly"防止用户随意输入。
十、总结
Tkinter 的核心使用思路:
text
创建根窗口
→ 创建控件(Label / Button / Entry / Canvas ...)
→ 用 pack / grid / place 布局
→ 用 command / bind 绑定事件
→ 用 after 做动画
→ 用变量类(StringVar / IntVar ...)双向绑定
→ 用 messagebox / filedialog / colorchooser 做交互
Canvas 核心流程:
text
创建 Canvas
→ create_xxx 创建图形项,得到 item id
→ itemconfig / coords / move / delete 管理
→ bind / tag_bind 处理事件
→ after 做动画
→ Scrollbar + scrollregion 做滚动
→ create_image / create_window 显示图片或嵌入控件