6. 菜单、对话框与多窗口
这是什么:菜单条(窗口顶部的 文件/编辑/帮助)、对话框(弹出要你确认或填东西的小窗)、多窗口(Toplevel 附属窗口)——让自制程序"像个正经软件"的三件套。
为什么用:第 5 章结束,你的程序已经有交互了,但操作全靠把按钮摆在脸上——功能一多界面就挤爆。菜单把功能收纳进顶栏,对话框负责"要输入、要确认、要选文件",Toplevel 负责"关于本程序"——这三样用熟,程序立刻从"玩具"升级成"工具"。
如何用:本章做一个迷你记事本,三件套全用上。
菜单条:顶栏收纳功能
import tkinter as tk
def say_hello():
print("hello") # 控制台里看效果(窗口程序没控制台也行)
root = tk.Tk()
root.title("菜单演示")
root.geometry("300x200")
menubar = tk.Menu(root)
filemenu = tk.Menu(menubar, tearoff=0)
filemenu.add_command(label="新建", command=say_hello)
filemenu.add_command(label="退出", command=root.quit)
filemenu.add_separator()
menubar.add_cascade(label="文件", menu=filemenu)
helpmenu = tk.Menu(menubar, tearoff=0)
helpmenu.add_command(label="关于",
command=lambda: print("迷你记事本 v1.0"))
menubar.add_cascade(label="帮助", menu=helpmenu)
root.config(menu=menubar)
root.mainloop()
你会看到:窗口顶部出现"文件 / 帮助"两个菜单,点开文件有"新建 —— 退出"(中间带分隔线)。
| 代码 | 作用 |
|---|---|
tk.Menu(...) |
建菜单;挂在 root 上的是菜单条本身,加进菜单条的是子菜单 |
add_command(label=..., command=...) |
加一项,点击执行 command |
add_cascade(label=..., menu=...) |
把子菜单挂到菜单条上 |
tearoff=0 |
关掉子菜单顶部那条可"撕下"的小虚线(现代界面都不要它) |
root.quit |
结束事件循环;关窗口用 root.destroy,日常差别极小 |
三种对话框:开箱即用
messagebox 问话、filedialog 选文件、simpledialog 要输入:
import tkinter as tk
from tkinter import messagebox, filedialog, simpledialog
root = tk.Tk()
root.withdraw() # 先藏起主窗口,让对话框直接弹出
messagebox.showinfo("提示", "你好,我是消息框")
answer = messagebox.askyesno("确认", "要删除这条记录吗?") # 返回 True/False
name = simpledialog.askstring("输入", "你叫什么名字?") # 取消返回 None
path = filedialog.askopenfilename( # 取消返回 ""
title="选一个文件",
filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")])
root.deiconify() # 把主窗口重新显示出来
root.mainloop()
你会看到:连着弹四个系统风格的小窗——提示、是否确认(点"否"试试)、输入名字、文件选择器。
| 函数 | 用途 | 返回值 |
|---|---|---|
showinfo / showwarning / showerror |
通知一句话 | None |
askyesno / askokcancel |
要用户拍板 | True / False |
askstring / askinteger / askfloat |
要一个输入 | 内容,取消为 None |
askopenfilename / asksaveasfilename |
要一个路径 | 路径字符串,取消为空串 |
取消不是失败,是常态:对话框的返回值先判空/判 False 再继续,否则
open("")直接崩——本章练习埋了这个雷。
多窗口:Toplevel
def open_about():
about = tk.Toplevel(root) # 附属窗口,独立可关
about.title("关于")
about.geometry("220x120")
tk.Label(about, text="迷你记事本 v1.0\n© 2026 青蛙编程网").pack(expand=True)
tk.Toplevel(root) 再建一个窗口,有自己的标题栏和关闭按钮;主窗关了就全体退出。"关于"面板、独立设置窗用它;别拿它当"新页面"把主窗关掉——新手最爱把 root 关光再 tk.Tk() 重开,那是重启程序,不是切页面。
迷你记事本 v1.0:三件套合体
import tkinter as tk
from tkinter import filedialog, messagebox
root = tk.Tk()
root.title("迷你记事本")
root.geometry("480x320")
editor = tk.Text(root)
editor.pack(fill="both", expand=True)
def new_file():
if messagebox.askyesno("新建", "当前内容未保存,确定清空?"):
editor.delete("1.0", "end")
def open_file():
path = filedialog.askopenfilename(filetypes=[("文本", "*.txt")])
if not path:
return # 用户点了取消
try:
with open(path, encoding="utf-8") as f:
content = f.read()
except OSError as e:
messagebox.showerror("出错", f"读不了:{e}")
return
editor.delete("1.0", "end")
editor.insert("1.0", content)
def save_file():
path = filedialog.asksaveasfilename(defaultextension=".txt")
if not path:
return
with open(path, "w", encoding="utf-8") as f:
f.write(editor.get("1.0", "end-1c")) # end-1c:别把末尾换行读进去
messagebox.showinfo("保存", "已存好!")
menu = tk.Menu(root)
fm = tk.Menu(menu, tearoff=0)
fm.add_command(label="新建", command=new_file)
fm.add_command(label="打开", command=open_file)
fm.add_command(label="保存", command=save_file, accelerator="Ctrl+S")
fm.add_separator()
fm.add_command(label="退出", command=root.quit)
menu.add_cascade(label="文件", menu=fm)
root.config(menu=menu)
root.bind("<Control-s>", lambda e: save_file())
root.mainloop()
你会看到:一个能用的记事本——能打字、菜单新建/打开/保存(弹标准文件对话框)、Ctrl+S 快捷键保存、退出前会问一句(自行加的 askyesno)。
editor.get("1.0", "end-1c") 里的 "1.0" / "end" / "end-1c"(末尾回退一个字符)是 Text 控件的"位置语法":行号.列号,第 1 章 Text 那行已预告。
记忆口诀:menu 管顶栏收纳,dialog 管要话要文件,Toplevel 管分身;见空就 return,取消不崩溃。
动手改
- 给记事本加"另存为"(提示:和保存共用函数,只是菜单多一项)和编辑菜单——"全选"(
editor.tag_add("sel", "1.0", "end")是歪招,正规做法是editor.event_generate("<<SelectAll>>"),试后者) - 把窗口标题同步成文件名:打开/保存后
root.title(f"{path} - 迷你记事本") - 挑战:窗口关闭时若有未保存内容就弹
askyesno问"确定退出?"(提示:root.protocol("WM_DELETE_WINDOW", 你的函数))
下一章:打包成 exe:PyInstaller 🐸