前言:
- 用python自带的GUI库tkinter开发东西比较敏捷,所以TKinter这个系列学习的目标是知道怎么用这个工具,同时可以加固对python的学习成果,了解python进行项目开发的方式。
- 本文中只涉及基础知识和基础开发相关控件。
一、第一部分基础知识:
1.1、基础概念
GUI:Graphical User Interface,用户图像界面
控件:用户图形界面中的元素,就是控件,比如,菜单栏、文本框、按钮等
普通python程序和GUI程序的区别:普通程序是按照顺序执行,GUI程序是事件驱动的程序,常见的GUI程序框架有Qt,TKinter,Java Swing等,他们的核心思想都是“等待事件发生后,再执行对应的代码”。
TKinter是python自带的GUI库
1.2、第一个tkinter程序:认识TKinter创建GUI程序的核心结构
- 第一个程序认识GUI程序和普通程序的不同
importtkinterastk''' 导入TKinter库,后面所有控件都从这里创建 '''importtimeif__name__=='__main__':print(f"程序开始")# 窗口创建前打印time.sleep(1)# 模拟耗时操作root=tk.Tk()# 创建主窗口,后面所有控件都放这个窗口对象中root.title("Hello Tkinter")# 设置窗口标题root.mainloop()# 进入消息循环,没有这个代码,程序一闪而过print(f"程序结束")# 窗口关闭后打印- TKinter程序执行流程:启动程序,导入库,创建对象,创建控件,给控件布局,进入消息循环,等待用户操作。
- 如果把制作GUI程序比喻成盖房的话,通过第一个程序,我们只是搭建了一个空房间,至于房间如何装修设计,实现什么功能,这就是后续要做的了。
1.3、第二个tkinter程序:装修TKinter程序中的主窗口对象root
- 第二个程序就可以开始装修我们用tkinger创建的窗口了。
- 窗口标题、大小、位置、背景颜色、窗口缩放、窗口尺寸、窗口状态
importtkinterastkif__init__='__main__':rt=tk.Tk()rt.title("修饰主窗口")# 窗口标题rt.geometry("800x800+100+50")# 窗口大小(800*800)和位置(距离左边100,上面50)rt.configure(bg="lightblue")# 修改窗口颜色,16进制配色也行#87CEFA# rt.resizable(False,False) # 锁死宽度,锁高度rt.minsize(400,400)# 设置最小尺寸rt.maxsize(1200,1200)# 设置最大尺寸rt.state("normal")# 设置窗口正常显示rt.mainloop()二、登陆页面项目驱动实战
2.1、第三个tkinter程序:写要给登录系统,学习一些重要控件
- 通过常用控件,写登录页面,用第一阶段学到的 Tkinter 知识,完成一个简单但完整的登录系统。
- 了解界面、控件、布局、事件、逻辑之间的关系:界面是容器,控件是元件,布局管摆放,事件当触发器,逻辑做处理,五者共同完成「用户操作→系统响应→界面更新」的 GUI 交互闭环。
| 概念 | 说明 |
|---|---|
| 界面 | 最外层窗口(Tk()实例),所有内容的载体,相当于整张“画布” |
| 控件 | 按钮、输入框、标签等可视化组件(Button/Entry/Label等),是用户交互的实体元件 |
| 布局 | pack / grid / place三类排布规则,决定控件在窗口中的位置、大小和排列,相当于“排版规则” |
| 事件 | 用户操作(点击、输入、关闭窗口)或系统触发的信号,是交互的触发开关 |
| 逻辑 | 绑定在事件上的 Python 函数,负责实际业务处理、数据计算和界面更新 |
- tkinter布局管理:
| 布局 | 特点 | 使用场景 |
|---|---|---|
pack() | 按方向排列布局,告诉tk"这个控件放到上面/下面/左边/右边" | 简单界面 |
grid() | 表格布局 | 登录、表单(最常用) |
place() | 绝对坐标布局 | 特殊场景 |
功能需求:
✅ 输入用户名
✅ 输入密码
✅ 点击登录验证
✅ 点击退出,关闭窗口
✅ 错误/成功弹窗开发流程:创建窗口、Frame布局、添加控件、添加事件逻辑。
使用Frame是因为后续主窗口中功能复杂了,功能区多了,不好区分控件,所以Frame(框架)就是窗口里面的小窗口。 计划设计三个Frame区域,第一个是标题区、第二个是中心区、第三个是按钮区。
在开发中,控件的使用逻辑,也是先创建,再布局。
Tkinter里面大部分控件都可以绑定事件,但绑定方式和事件类型有区别。按钮类控件主要用 command(命令回调),回调函数不需要传入事件对象event,但它只能绑定控件提供的特定动作。其他控件主要用 bind()去绑定控件创建的对象出现某一类事件时,bind() 是更底层的事件系统,监听的是控件发生了某种事件之后要去做什么,例如鼠标进入之后要做啥,这就需要将控件对象的某个事件和对应的自定义函数绑定起来,且自定义函数中要有event作为参数传入。
如下所示就是项目最终版的程序了,这个程序就是根据tkinter开发的一般模板来写的,之后写tkinter应用可以参考。更通用的tkinter项目开发,一般采用面向对象的方式。
importtkinterastkfromtkinterimportmessageboxfromtkinterimportttk# 引入tkinter中的ttk模块,ttk是tkinter的扩展模块,提供了更多的控件和样式''' tk和ttk的控件库各自不同,但是布局管理器是相同的,tkinter提供了三种布局管理器:pack、grid和place,ttk控件样式更丰富一些。 这个例子中没用到ttk '''classLoginWindow:def__init__(self):# 创建窗口self.rt=tk.Tk()# 创建主窗口self.rt.title("用户登陆系统")# 窗口标题self.rt.geometry("500x700+100+50")# 窗口大小(长*高)和位置(距离左边100,上面50)self.rt.resizable(False,False)# 锁死宽度,锁高度# 创建界面self.create_widgets()# 创建界面函数,其中创建控件最好都用self创建,后面就是可以调用的全局变量。defcreate_widgets(self):''' 布局划分==================================== '''# 顶部区域self.frame_top=tk.Frame(self.rt,bg="lightblue",width=500,height=100)# 创建顶部区域,设置背景颜色和高度self.frame_top.pack(fill=tk.X)# 顶部区域填充整个宽度self.frame_top.pack_propagate(False)# 关闭frame_top的自适应大小功能,防止frame_top的高度被子控件变大或者变小# 中间区域self.frame_middle=tk.Frame(self.rt,bg="lightgreen",width=500,height=400)# 创建中间区域,设置背景颜色和高度self.frame_middle.pack(fill=tk.X)# 中间区域填充整个宽度self.frame_middle.pack_propagate(False)# 关闭frame_middle的自适应大小功能,防止frame_middle的高度被子控件变大或者变小# 底部区域self.frame_bottom=tk.Frame(self.rt,bg="lightyellow",width=500,height=200)# 创建底部区域,设置背景颜色和高度self.frame_bottom.pack(fill=tk.X)# 底部区域填充整个宽度self.frame_bottom.pack_propagate(False)# 关闭frame_bottom的自适应大小功能,防止frame_bottom的高度被子控件变大或者变小# 使用pack布局管理器,将三个区域添加到主窗口中''' 顶部布局==================================== '''self.title_label=tk.Label(self.frame_top,text="用户登录系统",font=("微软雅黑",20),background="white")self.title_label.pack(pady=20,# 这是title_label这个控件距离frame_top这个父控件的上边距和下边距都是20像素# tkinter 默认 pack 会水平居中,此处移除无效的 padx)''' 中部布局==================================== '''# frame_middle_content 是用来让中间控件居中显示的容器,设置宽度为400像素,通过pack_propagate关闭了自适应功能self.frame_middle_content=tk.Frame(self.frame_middle,width=400,height=200,bg="lightyellow",bd=2,# 查看具体大小relief="solid")self.frame_middle_content.pack_propagate(False)self.frame_middle_content.pack(expand=True)# 设置grid整体居中self.frame_middle_content.grid_columnconfigure(0,weight=1)# 两个参数分别是列索引和权重,权重越大,列占据的空间越大self.frame_middle_content.grid_columnconfigure(1,weight=1)# 用户名及其输入部分self.user_label=tk.Label(self.frame_middle_content,text="用户名:",font=("微软雅黑",16))self.user_label.grid(row=0,column=0,padx=10,pady=30)self.user_entry=tk.Entry(self.frame_middle_content,width=25,font=("微软雅黑",16))self.user_entry.grid(row=0,column=1,padx=10,pady=30)# 给输入框对象绑定事件,当输入框获得焦点时,调用user_focus函数# 格式:控件.bind("事件类型", 事件函数)self.user_entry.bind("<FocusIn>",self.user_focus)# 密码及其输入部分self.password_label=tk.Label(self.frame_middle_content,text="密 码:",font=("微软雅黑",16))self.password_label.grid(row=1,column=0,padx=10,pady=30)self.password_entry=tk.Entry(self.frame_middle_content,width=25,font=("微软雅黑",16),show="*")self.password_entry.grid(row=1,column=1,padx=10,pady=30)# 给输入框对象绑定事件,当输入框获得焦点时,调用password_focus函数self.password_entry.bind("<FocusIn>",self.password_focus)# 查看控件大小(长宽)self.rt.update()# 更新窗口,确保所有控件都已经渲染完成print("frame_middle_content size:",self.frame_middle_content.winfo_width(),self.frame_middle_content.winfo_height())print("password_label size:",self.password_label.winfo_width(),self.password_label.winfo_height())''' 底部布局==================================== '''# 对比grid布局# frame_top.grid(row=0, column=0, sticky="ew") # 顶部区域占据第一行,填充整个宽度# frame_middle.grid(row=1, column=0, sticky="ew") # 中间区域占据第二行,填充整个宽度# frame_bottom.grid(row=2, column=0, sticky="ew") # 底部区域占据第三行,填充整个宽度# 对比place布局# frame_top.place(x=0, y=0, width=500, height=100) # 顶部区域放置在(0,0),宽度500,高度100# frame_middle.place(x=0, y=100, width=500, height=400) # 中间区域放置在(0,100),宽度500,高度400# frame_bottom.place(x=0, y=500, width=500, height=200) # 底部区域放置在(0,500),宽度500,高度200# 设置grid整体居中self.frame_bottom.grid_columnconfigure(0,weight=1)self.frame_bottom.grid_columnconfigure(1,weight=1)# 登录按钮login_button=tk.Button(self.frame_bottom,text="登录",font=("微软雅黑",16),width=10,height=1,command=self.function_login# 登录按钮点击事件,调用function_login函数)login_button.grid(row=0,column=0,padx=20,pady=50)# 退出按钮exit_button=tk.Button(self.frame_bottom,text="退出",font=("微软雅黑",16),width=10,height=1,command=self.rt.quit# 退出按钮点击事件,调用rt.quit函数)exit_button.grid(row=0,column=1,padx=20,pady=50)''' 通过事件绑定的函数==================================== '''defuser_focus(self,event):print("请输入用户名")defpassword_focus(self,event):print("请输入密码")# 定义绑定登录按钮点击事件的函数deffunction_login(self):username=self.user_entry.get()# 获取用户名输入框的内容password=self.password_entry.get()# 获取密码输入框的内容ifusername=="admin"andpassword=="123456":# 判断用户名和密码是否正确messagebox.showinfo("登录成功","欢迎,{}".format(username))# 弹出登录成功消息框else:messagebox.showerror("登录失败","用户名或密码错误")# 弹出登录失败消息框defrun(self):self.rt.mainloop()if__name__=="__main__":app=LoginWindow()app.run()- 后续进行大项目开发会用的一般文件分层方式如下:
login_system/
│
├── main.py
│
├── ui/
│ └── login_window.py
│
├── database/
│ └── user_db.py
│
└── config.py
2.2、总结tkinter开发中各关键要素之间的关系
- 承载关系:界面是根容器,所有控件必须依附于界面;布局作用于控件,把控件 “摆放” 到界面中。
- 触发关系:用户操作控件 → 产生对应事件 → 触发预先绑定的逻辑函数。
- 反馈闭环:逻辑执行后可修改控件属性(文字、颜色、内容),反过来更新界面显示,完成一次完整交互。