1 前言
使用python最舒服的地方就在于它内部有大量的库可供我们直接使用,而且使用起来还相当的方便。
前面章节我们一直围绕的都是基本语法的讲解,到目前为止,python大部分的基础语法我们就已经学习完了,已经完全可以开始写软件了。
而python这类脚本语言的一个痛点就在于,想要写一个带界面的软件并不容易,特别是想要写看起来很漂亮的软件。
不过python中确实存在大量的GUI库可以实现界面开发的功能,即使不那么好看。
GUI是Graphical User Interface(图形用户界面)的缩写,也就是我们平常电脑、手机上看到的各种软件界面,比如qq、微信等等。
而与之相对的就是CLI,是Command Line Interface(命令行接口)的简写,也就是到目前为止我们一直看到的输出字符的命令行窗口(也称终端)。
两者的区别非常明显,GUI适用于给那些对编程并不了解的人使用,它的编写会更加的复杂,使用起来会更加的简单,可以通过鼠标进行操作。
而CLI则更适用于给专业的人使用,你只能通过敲击字符来控制程序,编写起来更加的简单,但使用起来更加麻烦,甚至很多时候你还需要有相关的专业知识才行。
2 GUI原理
在正式写GUI程序前,了解它的原理是很有必要的,否则你写完代码依旧迷迷糊糊不知缘由,一旦出错,很难找到问题所在。
如果你了解C/C++,那么可以参考另外一篇文章学习如何从零制作一个自己的窗口:windows编程入门
从前面的编程中我们已经看到了,程序的执行流程就是从开始到结束,顺序执行下来的,所以你想要让一个程序一直运行起来,那就只能使用循环:
cmd = input('输入命令:')
while cmd != 'exit':
    print(f'你输入的命令为:{cmd}')
    cmd = input('输入命令:')
print('程序退出!')
结果为:

这就是一个最简单的CLI程序,你可以通过用户输入的不同命令,来执行不同的代码就行了。
而GUI程序虽然复杂一点,但本质上却同样如此:
- 运行程序、进入循环
- 等待用户的鼠标、键盘消息
- 处理鼠标键盘消息
这就是一个GUI程序的基本运行流程,它有一个非常重要的概念:消息。
这个消息就是当你鼠标移动的时候、当你键盘敲击的时候,你的电脑系统就会自动触发,并将这个消息发送给你这个GUI程序中,然后你处理这个消息就行了,就是这么的简单!
如果是C/C++语言,这一过程并不简单,因为消息纷繁复杂,但这是在python语言中,我们了解到这里就已经足够了
一个GUI程序的大概流程为:
- 初始化界面:提前布局好我们的界面
- 进入消息循环:一般GUI库会提供这样一个函数,然后程序运行到此就会卡住,等待系统不断发送消息过来
- 处理发送来的消息
GUI库有很多,原理都是如此,这是因为操作系统底层就是这么干的,而本文所要介绍的是python自带的GUI库:tkinter
如果觉得自带的不好用,当然你也可以去使用其它第三方的GUI库,都是可以的,这在python中非常简单。
注意,如果你安装python的时候是自定义安装,没有勾选td/tk and IDLE这个组件,那么请重新安装、并勾选上该组件,因为它就是我们本文要用到的tkinter模块。
3 tkinter基本使用
其官方教程可以点击这里查看,本文可能会很忽略,官方文档的内容一般都会更加详细。
3.1 主窗口
一个最简单的GUI程序代码如下:
from tkinter import Tk
window = Tk()
window.mainloop()
实际上就只有两行代码:
- Tk():通过该模块下的这个函数生成一个窗口实例对象
- 调用窗口的mainloop函数,进入消息循环
是不是非常的简单!

这个函数(类的初始化函数)有很多参数,但大多数情况下,你应该都用不上他们,而且这会涉及到很多底层的内容,避免加重学习负担,所以这里也不再过多介绍。
首先第一步肯定就是调整这个窗口的名称、大小、位置。
window = Tk()
window.title("第一个窗口") #设置窗口标题
window.geometry('600x400+200+100') #设置窗口大小、位置
window.mainloop()
设置标题比较简单,只是设置大小、位置稍微复杂一点。
函数geometry接受一个这种格式的字符串:宽 x 高 + x轴偏移 + y轴偏移
所以这里的'600x400+200+100'意思就是创建一个宽600,高400,x轴偏移200,y轴偏移100的窗口。
注意在计算机中,一般默认左上角为原点,左上角向右为x轴的正轴,左上角向下为y轴的正轴,而大多数时候初高中大学的数学课里面坐标轴一般选取的左下角,这一点是有区别的。
当然,偏移量比较麻烦,因为不同电脑的屏幕大小并不一样,所以一般都省略,只设置宽高就行了:
window.geometry('600x400') #设置窗口大小
如果想要居中显示,那就需要稍微计算一下:
window = Tk()
window.title("第一个窗口") #设置窗口标题
# 窗口的宽高
win_width=600
win_height=400
# 获取屏幕的宽度和高度
screen_width = window.winfo_screenwidth()
screen_height = window.winfo_screenheight()
# 计算窗口的位置
x = (screen_width - win_width) // 2  # 窗口的x坐标
y = (screen_height - win_height) // 2  # 窗口的y坐标
window.geometry(f'{win_width}x{win_height}+{x}+{y}')
window.mainloop()
主要是通过两个函数winfo_screenwidth与winfo_screenheight来获取当前电脑屏幕的宽高。
然后就可以用这两个数据计算出窗口左上角的坐标,也就是窗口偏移量。
注意这里除法用的是//,即整除的意思,比如3//2=1而不是1.5
计算思路比较简单,就是窗口的中心要在屏幕的中心,所以:
x+win_width/2=screen_width/2,移个项就行了,y轴同理
这里简单介绍了一个窗口应该如何使用,但仅仅只是这么一个窗口,是干不了什么事情的。
想要真正与用户交互,那就得用控件才行,比如常见的按钮、编辑框、进度条等等都是控件,它们都需要被放入到窗口中才能使用。
3.2 button
首先最简单的一个控件就是按钮了:
from tkinter import Tk, Button
def btn_click():
    print('按钮被点击了!')
window = Tk()
window.title("第一个窗口")
window.geometry('600x400')
btn = Button(window, text='这位是一个按钮', command=btn_click)
btn.pack()
window.mainloop()
需要关注的几个点:
- 使用控件,你得先将其导入,比如这里的from tkinter import Button
- 然后你就可以创建个按钮对象了:Button(),它有很多参数,而其中最主要最常用的就是这里用到的三个参数:父窗口、文本、以及回调函数
- 最后还需要设置显示在父窗口的位置:btn.pack(),这是按照父窗口垂直方向默认放置的。
父窗口填到第一个位置即可,text就是按钮显示的文本,command就是当按钮被点击时,要执行的函数,这就是在处理消息循环中的消息,接受到了用户点击按钮的消息,然后写一个函数在被点击的时候调用即可。
运行效果如图:

但很显然,这样摆放控件也太难看了,所以我们还需要学习一点布局的知识。
3.3 布局
tkinter库控件一共有三种布局方式:
- Pack布局管理器:按父窗口顺序摆放,一般用的较少,支持填充、扩展、对齐等选项。
- Grid布局管理器:通过将控件放置在网格中的单元格来布局窗口,更为常用。
- Place布局管理器:允许你以绝对位置和大小来放置控件,相比于Grid布局,会更加自由。
下面分别来介绍一下。
首先是pack布局,用到的函数就是pack这个函数:
from tkinter import Tk, Button, X
win = Tk()
win.title('测试布局')
win.geometry('600x400')
btn1 = Button(win, text="按钮1")
btn1.pack()
btn2 = Button(win, text="按钮2", )
btn2.pack(fill=X)  # 向x轴填充
btn3 = Button(win, text="按钮3")
btn3.pack(expand=True)  # 向四周膨胀,占据剩余的空间
win.mainloop()
这里用到了它两个比较常用的参数:
- fill:向哪一个方向填充,注意其值有- None、- X、- Y、- BOTH等参数,并且是从库- tkinter中导出来的
- expand:当父窗口大小变化时,它占据的范围变不变化?默认为- False
上面的代码运行结果为:

它当然不止有这两个参数,那么这些参数去哪里看呢?
这就用到了IDE另一个功能,可以跳转到函数定义去,你只需要启用Fn键的同时、按F12,即可跳转到对应的源码位置。
然后你就能看到下图的注释,看看你需要哪些就按照注释所说的内容进行添写即可:

注意其源码的写法,pack通过连等,最终等于了pack_configure这个函数的,所以我们应该看这个函数的定义、注释信息。
如果还不会用,那就问问chatgpt、或者浏览器搜一搜,都很容易得到答案。
然后是Grid管理器,函数名就是grid:
btn1 = Button(win, text="按钮1")
btn1.grid(row=0, column=0)
btn2 = Button(win, text="按钮2", )
btn2.grid(row=0, column=1, columnspan=2)
btn3 = Button(win, text="按钮3")
btn3.grid(row=1, column=0, rowspan=2)
它最重要的就两个参数:
- row:放在第几行
- column:放在第几列
至于columnspan与rowspan两个参数,则是用来合并单元格的,即:这个控件占用几行、或者几列,但这里由于由于控件较少,看不出太大的效果:

同样的,可按上面提到的方式查看其定义,就可以看到我们可以填写哪些参数:

最后一个Place布局,它最自由,你可以随意放置,函数名字就为place:
btn1 = Button(win, text="按钮1")
btn1.place(x=20, y=100)
btn2 = Button(win, text="按钮2", )
btn2.place(x=20, y=140, width=80)