之前,我们在 Pycharm 中都是在 IDLE 或命令提示窗口进行简单的输入输出,但当前流行的桌面应用程序大多数为图形化用户界面(Graphic User Interface,GUI),即通过鼠标对菜单、按钮等图形化元素触发指令,并从标签、对话框等图型化显示容器中获取人机对话信息。
Python自带的 tkinter 模块,实质上是一种面向对象的 GUI 工具包,提供了创建 GUI 应用程序的方法。 其图像化编程的基本步骤为:
1)导入 tkinter 模块;
2)创建 GUI 根窗体;
3)在跟窗体中添加人机交互控件并编写相应的函数;
4)在主事件循环中等待用户触发事件响应。
1. 我的第一个 Tkinter 窗口程序
例:编写程序,窗口大小为 350×200,标题为 “我的第一个 Tkinter 窗口”。
# 导入 thinter 库
import tkinter
# 创建顶层窗口对象
m = tkinter.Tk()
# 设置窗口标题
m.title("我的第一个 Tkinter 窗口")
# 设置窗口大小,350x200,注意不是*,而是字母x
m.geometry("350x200")
# 主事件循环
m.mainloop()
'''
第一句代码,import tkinter 导入 Tkinter 模块,如果使用 import tkinter as tk,
则后面代码中使用 tk.<函数名> 调用方法;如果使用 from tkinter import *,
则后面直接使用<函数名>调用方法。使用 Tkinter 的 GUI 程序必须先导入 Tkinter 模块,
以获得 Tkinter 的访问权。
第二句代码,m=tkinter.Tk() 创建一个顶层窗口对象。顶层对象是指在程序中独立显示的部分,
可以在 GUI 程序中创建多个顶层窗口,但其中只能有一个是根窗口。
第三局代码,m.title("我的第一个 Tkinter 窗口"),设置窗口标题。m 对象可以有多个方法
设置窗口其他属性,如窗口大小、窗口位置等。
第四句代码,设置窗口大小,使用 resizable(width=False, height=True) 可以控制窗口大小
是否改变。
第五句代码,m.mainloop() 进入主事件循环。这是一个无线循环,通常是程序的最后一段代码。
'''
2. 在窗口中添加组件
为窗口加入组件,创建并运行 Tkinter GUI 程序:
1)导入 Tkinter 模块;
2)创建一个顶层窗口对象;
3)在顶层窗口中加入 GUI 组件;
4)把 GUI 组件与事件处理代码相连;
5)进入主事件循环。
例:编写一个程序,点击窗口中的按钮,弹窗出现。
# 导入 thinter 库
import tkinter
import tkinter.messagebox
# 创建顶层窗口对象
m = tkinter.Tk()
# 设置窗口标题
m.title("我的第一个 Tkinter 窗口")
# 设置窗口大小,350x200,注意不是*,而是字母x
m.geometry("350x200")
# 单击按钮响应函数
def button_clicked():
tkinter.messagebox.showinfo("Message", "hello word!")
# 定义按钮
btn1 = tkinter.Button(m, text="hello", command=button_clicked)
btn1.pack()
# 主事件循环
m.mainloop()
'''
本程序先导入了 Tkinter 模块和模块的弹窗组件。
使用 btn1 = tkinter.Button(m, text="hello", command=button_clicked) 语句
定义一个按钮对象,括号中的属性参数:m 是定义按钮所在的窗口,text 是按钮的标题,
command 调用函数。
def button_clicked():tkinter.messagebox.showinfo("Message", "hello word!")
定义了一个函数,该函数的功能是弹出一个弹窗提示信息,弹窗名称是 “massage”,
提示信息是 “hello word!”
'''
3. 组件坐标布局管理器
窗口中的各组件需要我们自定义布局,就像网页的前端文件一样。组件的布局通常有三种方法:pack(顺序布局)、grid(行列布局)、place(坐标布局)。
3.1 pack 坐标布局管理器
pack 坐标布局管理器采用块的方式组织组件。pack 根据组件创建生成的顺序将子组件添加到父组件中,通过设置选项,可以控制子组件的位置等。采用 pack 的代码量最少,所以调用子组件的方法 pack 后,该子组件在其父组件中采用 pack 布局。
pack(option=value,...)
pack 方法提供的选项:
选项 | 作用 | 取值范围 |
side | 停靠在父组件的哪边 | top(默认值)、buttom、left、right |
anchor | 停靠对齐方式 | 对应东南西北中及四个角:n、s、w、e、center(默认值)、nw、sw、se、ne |
fill | 填充空间 | x、y、both、none |
expand | 扩展空间 | 0、1 |
ipadx、ipady | 组件在 x/y 方向上填充的空间大小 | 单位:c(厘米)、m(毫米)、i(英寸)、p(打印机的点) |
padx、pady | 组件外部在 x/y 方向上填充的空间大小 | 同上 |
例:使用 pack 方法编写一个用户登录窗口,要求有文本标题、文本框及两个按钮。
# 导入 thinter 库
from tkinter import *
import tkinter.messagebox
# 创建顶层窗口对象
m = tkinter.Tk()
# 设置窗口标题
m.title("登录")
# 界面分为上、中、下三个Frame,f1放置第一行标签和文本框
f1 = tkinter.Frame(m)
f1.pack()
# f2放置第二行标签和文本框
f2 = tkinter.Frame(m)
f2.pack()
# f3放置第三行两个按钮
f3 = tkinter.Frame(m)
f3.pack()
# 标签和单行文本框都放置在f1中,左停靠
Label(f1, text="用户名").pack(side=LEFT)
Entry(f1).pack(side=LEFT)
# 标签和单行文本框都放置在f2中,左停靠
Label(f2, text="密码").pack(side=LEFT)
Entry(f2, show="*").pack(side=LEFT)
# 两个按钮都放置在f3中
Button(f3, text="登录").pack(side=RIGHT)
Button(f3, text="取消").pack(side=LEFT)
# 主事件循环
m.mainloop()
3.2 grid 坐标布局管理器
grid 坐标布局管理器采用控制行列的方式组织组件。grid 坐标布局采用表格形式的布局,可以实现复杂的页面。调用子组件的方法为 grid,该子组件在其父组件中采用 grid 布局。
grid(option=value, ...)
grid 方法提供的选项:
选项 | 作用 | 取值范围 |
column | 单元格列号 | 从0开始的正整数 |
columnspan | 列跨度 | 正整数 |
row | 单元格行号 | 从0开始的正整数 |
rowspan | 行跨度 | 正整数 |
ipadx、ipady | 组件在 x/y 方向上填充的空间大小 | 单位:c(厘米)、m(毫米)、i(英寸)、p(打印机的点) |
padx、pady | 组件外部在 x/y 方向上填充的空间大小 | 单位:c(厘米)、m(毫米)、i(英寸)、p(打印机的点) |
sticky | 组件紧贴单元格东南西北中及四个角 | n、s、w、e、center(默认值)、nw、sw、se、ne,可以紧贴多个边角,如 tk.N+tk.S |
例:使用 grid 方法编写一个用户登录窗口,要求有文本标题、文本框及两个按钮。
# 导入 thinter 库
from tkinter import *
import tkinter.messagebox
# 创建顶层窗口对象
m = tkinter.Tk()
# 设置窗口标题
m.title("登录")
# 用户名标签放置在第0行第0列
Label(m, text="用户名").grid(row=0, column=0)
# 用户名文本框放置在第0行第1列,跨两列
Entry(m).grid(row=0, column=1, columnspan=2)
# 密码标签放置在第1行第0列
Label(m, text="密码").grid(row=1, column=0)
# 用户名文本框放置在第1行第1列,跨两列
Entry(m, show="*").grid(row=1, column=1, columnspan=2)
# 登录按钮右侧紧贴
Button(m, text="登录").grid(row=3, column=1, sticky=E)
# 取消按钮左侧紧贴
Button(m, text="取消").grid(row=3, column=2, sticky=W)
# 主事件循环
m.mainloop()
3.3 place 坐标布局管理器
place 坐标布局管理器允许指定组件的大小与位置。place 的优点是可以精确控制组件的位置,不足之处是改变窗口大小时,子组件不能随之灵活改变大小。调用子组件的方法 place,则该子组件在其父组件中采用 place 布局。
place(option;...)
place 方法提供的选项:
选项 | 作用 | 取值范围 |
x,y | 绝对坐标 | 从0开始的正整数 |
relx,rely | 相对坐标 | 取0.0~1.0之间的值 |
width,height | 宽和高的绝对值 | 正整数,单位 px |
relwidth,relheight | 宽和高的相对值 | 取0.0~1.0之间的值 |
anchor | 对齐方式,对应东南西北中及四个角 | n、s、w、e、center(默认值)、nw、sw、se、ne |
例:使用 place 方法编写一个用户登录窗口,要求有文本标题、文本框及两个按钮。
# 导入 thinter 库
from tkinter import *
import tkinter.messagebox
# 创建顶层窗口对象
m = tkinter.Tk()
# 设置窗口标题
m.title("登录")
m["width"] = 200
m["height"] = 80
# 用户名标签,绝对坐标(1,1)
Label(m, text="用户名", width=6).place(x=1, y=1)
# 用户名文本框,绝对坐标(45,1)
Entry(m, width=20).place(x=45, y=1)
# 密码标签,绝对坐标(1,20)
Label(m, text="密码", width=6).place(x=1, y=20)
# 用户名文本框,绝对坐标(45,20)
Entry(m, show="*", width=20).place(x=45, y=20)
# 登录按钮,绝对坐标(40,40)
Button(m, text="登录", width=8).place(x=40, y=40)
# 取消按钮,绝对坐标(110,40)
Button(m, text="取消", width=8).place(x=110, y=40)
# 主事件循环
m.mainloop()
4. 事件处理
用户通过鼠标和键盘与图形用户界面交互时,会触发事件。Tkinter 事件采用放置于(<>)内的字符串表示,称为事件系列。
<[modifier-]...type[-detail]>
可选的 modifier 用于组合键定义,具体如下:
# 同时按下Ctrl、Shift、Alt和A四个键
<Control-Shift-Alt-KeyPress-A>
# 按下A键
<KeyPress-A>
# 单击鼠标左键
<Button-1>
# 双击鼠标左键
<Double-Button-1>
'''也可以使用短格式表示事件,"<1>"等同于"<Button-1>;
"x"等同"<KeyPress-x>""'''
4.1 事件绑定
调用组件对象实例方法 bind,可以为指定组件实例绑定事件。
例:编写一个程序,当使用鼠标左键单击容器时获得坐标。
# 导入 thinter 库
from tkinter import *
import tkinter.messagebox
# 创建顶层窗口对象
m = tkinter.Tk()
def callback(event):
print(event.x, event.y)
frame = tkinter.Frame(m, width=180, height=150)
frame.bind("<Button-1>", callback)
frame.pack()
# 主事件循环
m.mainloop()
5. Tkinter 库的常用组件
组件 | 名称 | 作用 |
---|---|---|
Button | 按钮 | 单击触发事件 |
Canvas | 画布 | 绘制图形或绘制特殊组件 |
Checkbutton | 复选框 | 多项选择 |
Entry | 输入框 | 接收单行文本输入 |
Frame | 框架 | 用于组件分组 |
Label | 标签 | 单行文本显示 |
Listbox | 列表框 | 显示文本列表 |
Menu | 菜单 | 创建菜单命令 |
Menubutton | 菜单按钮组件 | 显示菜单项 |
Message | 消息 | 多行文本标签,类似于 Label |
Radiobutton | 单选按钮 | 单项选择 |
Scale | 滑块 | 默认垂直方向,鼠标拖动改变数值形成可视化交互 |
Scrollbar | 滑动条 | 默认垂直方向,鼠标拖动改变数值,可与 Text、Listbox、Canvas 等组件配合形成可视化交互 |
Text | 文本框 | 接收或输出多行文本 |
Toplevel | 新建窗体容器 | 在顶层创建新窗体 |