Python GUI 之Tkinter小结
背景 本主在使用Python的过程中一切都是奔着产品去的,中间经历了Tkinter、Flask web、微信小程序。最初单一的Tkinter无法解决用户系统、Flask仅适用轻量级封装、微信小程序受制于微信体系,一圈玩下来,又返回到Tkin…
背景
本主在使用Python的过程中一切都是奔着产品去的,中间经历了Tkinter、Flask web、微信小程序。最初单一的Tkinter无法解决用户系统、Flask仅适用轻量级封装、微信小程序受制于微信体系,一圈玩下来,又返回到Tkinter,顺利串联了三者,因此有必要对Tkinter做一个小结。
控件大小
from tkinter import *
# 一般在测量 tkinter 控件内的大小时,是以像素为单位。下面定义 Button 控件的文字与边框之间的水平距离为 20 像素:
win=Tk()
Button(win,padx=20,text="关闭",command=win.quit).pack()
win.mainloop()
from tkinter import *
# 也可以使用其他测量单位,如 c(厘米)、m(毫米)、i(英寸=2.54cm)、p(点,1p = 1 / 72英寸)。示例代码如下所示:
win=Tk()
Button(win,padx=20,text="关闭",command=win.quit).pack()
Button(win,padx="2c",text="关闭",command=win.quit).pack()
Button(win,padx="8m",text="关闭",command=win.quit).pack()
Button(win,padx="2i",text="关闭",command=win.quit).pack()
Button(win,padx="20p",text="关闭",command=win.quit).pack()
win.mainloop()Frame
参数
Frame(master=None, **options) (class)
master -- 父组件
**options -- 组件选项,下方表格详细列举了各个选项的具体含义和用法:
| 选项 | 含义 |
| background | 1. 设置 Frame 组件的背景颜色2. 默认值由系统指定3. 为了防止更新,可以将颜色值设置为空字符串 |
| bg | 跟 background 一样 |
| borderwidth | 1. 指定 Frame 的边框宽度2. 默认值是 0 |
| bd | 跟 borderwidth 一样 |
| class_ | 默认值是 Frame |
| colormap | 1. 有些显示器只支持 256 色(有些可能更少),这种显示器通常提供一个颜色映射来指定要使用要使用的 256 种颜色2. 该选项允许你指定用于该组件以及其子组件的颜色映射3. 默认情况下,Frame 使用与其父组件相同的颜色映射4. 使用此选项,你可以使用其他窗口的颜色映射代替(两窗口必须位于同个屏幕并且具有相同的视觉特性)5. 你也可以直接使用 "new" 为 Frame 组件分配一个新的颜色映射6. 一旦创建 Frame 组件实例,你就无法修改这个选项的值 |
| container | 1. 该选项如果为 True,意味着该窗口将被用作容器,一些其它应用程序将被嵌入 2. 默认值是 False |
| cursor | 1. 指定当鼠标在 Frame 上飘过的时候的鼠标样式2. 默认值由系统指定 |
| height | 1. 设置 Frame 的高度2. 默认值是 0 |
| highlightbackground | 1. 指定当 Frame 没有获得焦点的时候高亮边框的颜色2. 默认值由系统指定,通常是标准背景颜色 |
| highlightcolor | 1. 指定当 Frame 获得焦点的时候高亮边框的颜色2. 默认值由系统指定 |
| highlightthickness | 1. 指定高亮边框的宽度2. 默认值是 0(不带高亮边框) |
| padx | 水平方向上的边距 |
| pady | 垂直方向上的边距 |
| relief | 1. 指定边框样式2. 默认值是 "flat"3. 另外你还可以设置 "sunken","raised","groove" 或 "ridge"4. 注意,如果你要设置边框样式,记得设置 borderwidth 或 bd 选项不为 0,才能看到边框 |
| takefocus | 1. 指定该组件是否接受输入焦点(用户可以通过 tab 键将焦点转移上来)2. 默认值是 False |
| visual | 1. 为新窗口指定视觉信息2. 该选项没有默认值 |
| width | 1. 设置 Frame 的宽度2. 默认值是 0 |
import tkinter as tk
master = tk.Tk()
tk.Label(text="天王盖地虎").pack()
separator = tk.Frame(height=2, bd=1, relief="sunken")
separator.pack(fill="x", padx=5, pady=5)
tk.Label(text="小鸡炖蘑菇").pack()
master.mainloop()LabelFrame
参数
LabelFrame(master=None, **options) (class)
master -- 父组件
**options -- 组件选项,下方表格详细列举了各个选项的具体含义和用法:
| 选项 | 含义 |
| background | 1. 设置 LabelFrame 组件的背景颜色2. 默认值由系统指定3. 为了防止更新,可以将颜色值设置为空字符串 |
| bg | 跟 background 一样 |
| borderwidth | 1. 指定 LabelFrame 的边框宽度2. 默认值是 2 像素 |
| bd | 跟 borderwidth 一样 |
| class | 默认值是 LabelFrame |
| colormap | 1. 有些显示器只支持 256 色(有些可能更少),这种显示器通常提供一个颜色映射来指定要使用要使用的 256 种颜色2. 该选项允许你指定用于该组件以及其子组件的颜色映射3. 默认情况下,Frame 使用与其父组件相同的颜色映射4. 使用此选项,你可以使用其他窗口的颜色映射代替(两窗口必须位于同个屏幕并且具有相同的视觉特性)5. 你也可以直接使用 "new" 为 Frame 组件分配一个新的颜色映射6. 一旦创建 Frame 组件实例,你就无法修改这个选项的值 |
| container | 1. 该选项如果为 True,意味着该窗口将被用作容器,一些其它应用程序将被嵌入 2. 默认值是 False |
| cursor | 1. 指定当鼠标在 LabelFrame 上飘过的时候的鼠标样式2. 默认值由系统指定 |
| foreground | 1. 设置 LabelFrame 的文本颜色2. 默认值由系统指定 |
| fg | 跟 foreground 一样 |
| font | 1. 指定 LabelFrame 中文本的字体2. 默认值由系统指定 |
| height | 1. 设置 LabelFrame 的高度2. 单位是像素 |
| highlightbackground | 1. 指定当 LabelFrame 没有获得焦点的时候高亮边框的颜色2. 默认值由系统指定,通常是标准背景颜色 |
| highlightcolor | 1. 指定当 LabelFrame 获得焦点的时候高亮边框的颜色2. 默认值由系统指定 |
| highlightthickness | 1. 指定高亮边框的宽度2. 默认值是 1 或 2 像素 |
| labelanchor | 1. 控制文本在 LabelFrame 的显示位置2. "n", "ne", "e", "se", "s", "sw", "w", "nw", 或 "center" 来定位(ewsn代表东西南北,上北下南左西右东)3. 默认值是 NW |
| labelwidget | 1. 指定一个组件替代默认的文本 Label2. 如果同时设置此选项和 text 选项,则忽略 text 选项的内容 |
| padx | 1. 指定 FrameLabel 水平方向上的额外间距(内容和边框间)2. 默认值是 0 |
| pady | 1. 指定 FrameLabel 垂直方向上的额外间距(内容和边框间)2. 默认值是 0 |
| relief | 1. 指定边框样式2. 默认值是 "groove"3. 另外你还可以设置 "flat","sunken","raised" 或 "ridge"4. 注意,如果你要设置边框样式,记得设置 borderwidth 或 bd 选项不为 0,才能看到边框 |
| takefocus | 1. 指定该组件是否接受输入焦点(用户可以通过 tab 键将焦点转移上来)2. 默认值是 False |
| text | 1. 指定 LabelFrame 显示的文本2. 文本可以包含换行符 |
| visual | 1. 为新窗口指定视觉信息2. 该选项没有默认值 |
| width | 1. 设置 LabelFrame 的宽度2. 默认值是 0 |
import tkinter as tk
master = tk.Tk()
group = tk.LabelFrame(master, text="你从哪里得知CSDN?", padx=5, pady=5)
group.pack(padx=10, pady=10)
v = tk.IntVar()
r1 = tk.Radiobutton(group, text="同学/同事介绍", variable=v, value=1).pack(anchor="w")
r2 = tk.Radiobutton(group, text="老婆大人介绍", variable=v, value=2).pack(anchor="w")
r3 = tk.Radiobutton(group, text="老师/学长介绍", variable=v, value=3).pack(anchor="w")
master.mainloop()

pack
| 属性 | 属性简析 | 备注 | 其他 |
| fill | 设置组件是否向水平或垂直方向填充,包含X、Y、BOTH、NONE | fill = X(水平方向填充)fill = Y(垂直方向填充)fill = BOTH(水平和垂直)NONE 不填充 | |
| expand | 设置组件是否展开,当值为YES时,side选项无效。组件显示在父容器中心位置;若fill选项为BOTH,则填充父组件的剩余空间。它表示某个控件在fill那个方向,要不要把空白的地方分配给它 | YES 、NO(1、0) | 若expand=True或者expand=1,表示在fill那个方向,把空白处都分给这个控件,让它尽量占满。 若expand=False或者expand=0,表示在fill那个方向,有空也不给它。 |
| side | 设置组件的对齐方式 | LEFT、TOP、RIGHT、BOTTOM | 值为左、上、右、下 |
| ipadx、ipady | 设置x方向(或者y方向)内部间隙(子组件之间的间隔),它表示某个控件的内边距,即控件边缘和这个控件内容(文字图片什么的)的间距 | 可设置数值,默认是0 | 非负整数,单位为像素 |
| padx、pady | 设置x方向(或者y方向)外部间隙(与之并列的组件之间的间隔),它表示某个控件的外边距,即控件边缘和这个控件所在容器之间的间距 | 可设置数值,默认是0 | 非负整数,单位为像素 |
| anchor | 锚选项,当可用空间大于所需求的尺寸时,决定组件被放置于容器的何处,它表示某个控件在容器里的摆放方式,是左还是右,是上还是下 | N、E、S、W、NW、NE、SW、SE、CENTER(默认值为CENTER) | 表示八个方向以及中心 |
from tkinter import *
#主窗口
win = Tk()
#第一个窗体
frame1 = Frame (win, relief=RAISED, borderwidth=0)
frame1 .pack(side=TOP, fill=BOTH, ipadx=13, ipady=13, expand=0)
Button(frame1,text="Button 1") .pack(side=LEFT, padx=13, pady=13)
Button(frame1, text="Button 2") .pack(side=LEFT, padx=13, pady=13)
Button(frame1, text="Button 3") .pack (side=LEFT, padx=13, pady=13)
#第二个窗体
frame2 = Frame (win, relief=RAISED, borderwidth=1)
frame2 . pack (side=BOTTOM, fill=NONE, ipadx="1c", ipady="1c", expand=1)
Button (frame2, text="Button 4") .pack (side=RIGHT, padx="1c", pady="1c")
Button (frame2,text="Button 5") .pack (side=RIGHT, padx="1c", pady="1c")
Button (frame2,text="Button 6") .pack (side=RIGHT, padx="1c", pady="1c")
#第三个窗体
frame3 = Frame (win, relief=RAISED, borderwidth=2)
frame3. pack (side=LEFT, fill=X, ipadx="0.1i", ipady="0.1i", expand=1)
Button (frame3, text="Button 7") .pack(side=TOP, padx="0.1i", pady="0.1i")
Button (frame3, text="Button 8") .pack(side=TOP, padx="0.1i", pady="0.1i")
Button(frame3, text="Button 9") .pack(side=TOP, padx="0.1i", pady="0.1i")
#第四个窗体
frame4 = Frame (win, relief=RAISED, borderwidth=3)
frame4. pack (side=RIGHT, fill=Y, ipadx="13p", ipady="13p", expand=1)
Button(frame4, text="Button 13") . pack (side=BOTTOM, padx="13p",
pady="13p")
Button (frame4, text="Button 11") .pack (side=BOTTOM, padx="13p" ,
pady="13p")
Button (frame4, text="Button 12") .pack (side=BOTTOM, padx="13p",
pady="13p")
#开始窗口的事件循环
win . mainloop()
grid
| 属性 | 属性简析 | 实例 |
| row和column | 它表示某个控件要放在第几行网格或第几列网格,下标都是从0开始计的 | xxx.grid(column=1,row=1) |
| rowspan和columnspan | 它表示某个控件将会竖着跨几行或横着跨几列,默认都是1 | xxx.grid(column=1,row=1,columnspan=2)xxx.grid(column=1,row=1,rowspan=2) |
| padx和pady | 它表示某个控件的外边距,即控件边缘和这个控件所在容器之间的间距,单位是像素 | xxx.grid(column=1,row=1,padx=10)xxx.grid(column=1,row=1,pady=10) |
| ipadx和ipady | 它表示某个控件的内边距,即控件边缘和这个控件内容(文字图片什么的)的间距,单位是像素 | xxx.grid(column=1,row=1,ipadx=10)xxx.grid(column=1,row=1,ipady=10) |
| sticky | 它表示某个控件在网格里的摆放方式,是左还是右,是上还是下,即使窗口被拉大也会按照指定方向对齐 |
若sticky=N,表示North,尽可能往北面/上面停靠。 若sticky=S,表示South,尽可能往南面/下面停靠。若sticky=W,表示West,尽可能往西边/左边停靠。若sticky=E,表示East,尽可能往东边/右边停靠。若sticky=NS,表示NorthSouth,尽可能往南北方向/上下拉伸。若sticky=EW,表示EastWest,尽可能往东西方向/左右拉伸。若sticky=CENTER,尽可能往中心停靠。 |
from tkinter import *
#主窗口
win = Tk()
#创建窗体
frame = Frame (win, relief=RAISED, borderwidth=2)
frame.pack (side=TOP, fill=BOTH, ipadx=5, ipady=5, expand=1)
#创建按钮数组
for i in range (5):
for j in range (5):
Button (frame, text=" (" + str(i) + ","+ str(j)+ ")") .grid(row=i,column=j )
#开始窗口的事件循环
win. mainloop()
主窗口布局
from tkinter import *
#主窗口
win = Tk()
win.title('微信:civilpy')
winWidth = 700
winHeight = 350
# 获取屏幕分辨率(像素)
screenWidth = win.winfo_screenwidth()
screenHeight = win.winfo_screenheight()
x = int((screenWidth - winWidth) / 2)
y = int((screenHeight - winHeight) / 2)
# 设置窗口初始位置在屏幕居中
win.geometry("%sx%s+%s+%s" % (winWidth, winHeight, x, y))
# 设置窗口图标
win.iconbitmap("./images/favicon.ico")
# 设置窗口宽高固定
win.resizable(0, 0) # 防止用户调整尺寸
其他控件
1、title:设置窗口的标题
| 属性 | 属性简析 | 实例 |
| title | 设置窗口标题 | title(‘xxxxx’) |
| geometry | 设置窗口大小,中间不能是*,而是x | geometry('200x100') |
| resizable | 设置窗口是否可以变化高(height)、 宽(width),True为可以变化,False为不可变化 | resizable(width=False, height=True) |
2、Label:标签
| 属性 | 属性简析 | 实例 |
| text | 需要在界面显示的Label标签内容 | Label(root,text=‘xxxxx’) |
| height | 组件的高度(所占行数) | Label(root,text=‘xxxxx’,height=2) |
| width | 组件的宽度(所占字符个数) | Label(root,text=‘xxxxx’,height=2,width=20) |
| fg | 前景字体颜色 | Label(root,text=‘xxxxx’,fg='blue')---显示字体为蓝色 |
| bg | 背景颜色 | Label(root,text=‘xxxxx’,bg=‘red’)---显示背景为红色 |
| justify | 多行文本的对齐方式,可选参数为: LEFT、 CENTER、RIGHT,分别是向左、居中、向右对齐 | Label(root,text=‘xxxxx’,justify=tk.LEFT) |
| padx | 文本左右两侧的空格数(默认为1) | Label(root,text=‘xxxxx’,padx=5) |
| pady | 文本上下两侧的空格数(默认为1) | Label(root,text=‘xxxxx’,pady=5) |
| font | 设置字体格式和大小 | Label(root,text=‘xxxxx’,font=("微软雅黑", 12)) |
| photo | 设置背景图片,事先需要指定图片路径 | photo=tk.PhotoImage(file='指定图片路径')Label(root,text=‘xxxxx’,image=photo) |
| compound | 图像背景图位置,可选参数为:botton、top、right、left、center(下、上、右、左、文字覆盖图像) | photo=tk.PhotoImage(file='指定图片路径')Label(root,text=‘xxxxx’,image=photo,compound=center) |
3、Button:按钮
| 属性 | 属性简析 | 实例 |
| text | 按钮图标显示内容 | Button(root,text='xxxx') |
| height | 组件的高度(所占行数) | Button(root,text='xxxx',height=2) |
| width | 组件的宽度(所占字符个数) | Button(root,text='xxxx',width=20) |
| fg | 前景字体颜色 | Button(text='xxxx',fg='blue')---显示按钮字体颜色为蓝色 |
| bg | 背景颜色 | Button(root,text='xxxx',bg='red')---显示按钮背景为红色 |
| activebackground | 按钮按下时的背景颜色 | Button(root,text='xxxx',activebackground='grey') |
| activeforeground | 按钮按下时的前景字体颜色 | Button(root,text='xxxx',activeforeground='white') |
| justify | 多行文本的对齐方式,可选参数为: LEFT、 CENTER、RIGHT,分别是向左、居中、向右对齐 | Button(root,text=‘xxxxx’,justify=tk.LEFT) |
| padx | 文本左右两侧的空格数(默认为1) | Button(root,text='xxxx',padx=10) |
| pady | 文本上下两侧的空格数(默认为1) | Button(root,text='xxxx',pady=10) |
| command | 按钮触发执行的命令(函数) | Button(root,text='xxxx',command=函数) |
4、Entry:输入框
| 属性 | 属性简析 | 实例 |
| width | 组件的宽度(所占字符个数) | Entry(root,width=20) |
| fg | 前景字体颜色 | Entry(root,fg='blue') |
| bg | 背景颜色 | Entry(root,bg='blue') |
| show | 将Entry框中的文本替换为指定字符,用于输入密码等,如设置 show="*" | Entry(root,show="*") |
| state | 设置组件状态,默认为normal,可设置为:disabled—禁用组件,readonly—只读 | Entry(root,state=readonly) |
| textvariable | 指定变量,需要事先定义一个变量,在Entry进行绑定获取变量的值 |
text=tk.StringVar() Entry(root,textvariable=text) |
5、Radiobutton:单选框
| 属性 | 属性简析 | 实例 |
| text | 单选框文本显示内容 | Radiobutton(root,text='xxxx') |
| variable | 单选框索引变量,通过变量的值确定哪个单选框被选中。一组单选框使用同一个索引变量,需要事先设定一个变量 |
color=tk.StringVar() Radiobutton(root,variable=color) |
| value | 单选框选中时设定变量的值 |
color=tk.StringVar() Radiobutton(root,variable=color,value='red') |
| command | 单选框选中时执行的命令(函数) |
color=tk.StringVar() Radiobutton(root,variable=color,value='red',command=函数) |
6、Checkbuttion:复选框
| 属性 | 属性简析 | 实例 |
| text | 复选框显示的文本 | Checkbutton(root,text='xxxx') |
| variable | 复选框索引变量,通过变量的值确定哪些复选框被选中。每个复选框使用不同的变量,使复选框之间相互独立,事先需要定义不同的变量 |
typeBlod=tk.IntVar() Checkbutton(root,variable=typeBlod) |
| onvalue | 复选框选中(有效)时变量的值,可以通过计算值来判断分支不同的效果,计算值由自己设定 |
typeBlod=tk.IntVar() Checkbutton(root,variable=typeBlod,onvalue=1) |
| offvalue | 复选框未选中(无效)时变量的值,可以通过计算值来判断分支不同的效果,一般设置为0 |
typeBlod=tk.IntVar() Checkbutton(root,variable=typeBlod,onvalue=1,offvalue=0) |
| command | 复选框选中时执行的命令(函数) |
typeBlod=tk.IntVar() Checkbutton(root,variable=typeBlod,onvalue=1,offvalue=0,command=函数) |
7、Text:文本框
| 属性 | 属性简析 | 实例 | 备注 |
| t.insert(mark, 内容) | 插入文本信息,mark可以是行号,或者特殊标识 |
t=tk.Text() t.insert(END,'插入的文本信息') |
INSERT:光标的插入点 CURRENT:鼠标的当前位置所对应的字符位置END:这个Textbuffer的最后一个字符SEL_FIRST:选中文本域的第一个字符,如果没有选中区域则会引发异常SEL_LAST:选中文本域的最后一个字符,如果没有选中区域则会引发异常 |
| t.delete(mark1, mark2) | 删除文本信息 |
INSERT:光标的插入点CURRENT:鼠标的当前位置所对应的字符位置 END:这个Textbuffer的最后一个字符SEL_FIRST:选中文本域的第一个字符,如果没有选中区域则会引发异常SEL_LAST:选中文本域的最后一个字符,如果没有选中区域则会引发异常 |
8、messagebox
消息弹出框用于info、warning、error提示框的弹出使用的,我们可以根据自己的需求来使用
| 属性 | 属性简介 | 实例 |
| showinfo | info信息提示,弹出提示框 | msgbox.showinfo("INFO","Showinfo test"),INFO是提示框title,Showinfo test是提示框内容 |
| showwarning | warning警告信息提示,弹出警告框 | msgbox.showwarning("WARNING","Warning test"),WARNING是警告框title,Warning test是警告框内容 |
| showerror | error错误信息提示,弹出错误框 | msgbox.showerror("ERROR","Error test"),ERROR是错误框title,Error test是错误框内容 |
| askquestion | 提问窗口提示 | msgbox.askquestion("Question","Askquestion test") |
| askokcancel | 确定与取消窗口提示 | msgbox.askokcancel("OkCancel","Askokcancel test") |
| askyesno | 确定与取消窗口提示 | msgbox.askretrycancel("Retry","Askretrycancel test") |
| askretrycancel | 重试与取消窗口提示 | msgbox.askretrycancel("Retry","Askretrycancel test") |
Tkinter实现简易的聊天窗口(2021-1-15更新)
from tkinter import *
import datetime
import time
root=Tk ()
root.title('微信:civilpy与xyz聊天中')
winWidth = 560
winHeight = 460
# 获取屏幕分辨率(像素)
screenWidth = root.winfo_screenwidth()
screenHeight = root.winfo_screenheight()
x = int((screenWidth - winWidth) / 2)
y = int((screenHeight - winHeight) / 2)
# 设置窗口初始位置在屏幕居中
root.geometry("%sx%s+%s+%s" % (winWidth, winHeight, x, y))
# 设置窗口图标
root.iconbitmap("./images/favicon.ico")
# 设置窗口宽高固定
root.resizable(0, 0) # 防止用户调整尺寸
#发送按钮事件
def sendmessage() :
#在聊天内容上方加一行,显示发送人及发送时间
msgcontent ='我: ' + time.strftime ("%Y-%m-%d %H:%M:%S", time.localtime())+'\n'
text_msglist.insert (END, msgcontent, 'green')
text_msglist.insert (END, text_msg.get('0.0', END) )
text_msg.delete('0.0', END)
#创建几个frame作为容器
frame_left_top= Frame (width=380, height=270, bg='white')
frame_left_center= Frame (width=380, height=130, bg='white' )
frame_left_bottom= Frame (width=380,height=50)
frame_right = Frame (width=170,height=400,bg='white')
##创建需要的几个元素
text_msglist= Text (frame_left_top)
text_msg= Text (frame_left_center)
button_sendmsg= Button(frame_left_bottom,padx=20 ,text=('发送') ,command= sendmessage)
#创建一一个绿色的tag
text_msglist.tag_config('green', foreground='#008B00')
#使用grid设置各个容器的位置
frame_left_top.grid (row=0,column=0, padx=2,pady=5)
frame_left_center.grid (row=1, column=0, padx=2, pady=5)
frame_left_bottom.grid (row=2,column=0, columnspan=2, padx=2, pady=5)
frame_right.grid(row=0, column=1, rowspan=2, padx=2, pady=5)
frame_left_top.grid_propagate (False) # 防止框架会将其自身尺寸扩大到标签小部件
frame_left_center.grid_propagate (False) # 防止框架会将其自身尺寸扩大到标签小部件
# frame_left_bottom.grid_propagate (False)
#把元素填充进frame
text_msglist.grid()
text_msg.grid()
button_sendmsg.grid(sticky='EW')
#主事件循环
root.mainloop ()结语
在完成一个产品的过程中,还包含了很多细节的设计,就不在这里一一展开,感兴趣的道友可以看看我的制成品,其中包含了我2020年的技能树,兴许可以启发你的一些Idea:
本主2020年的3个封装作品下载链接:
https://pan.baidu.com/s/1kj29pFjLniQ9THbUSZMNlA
提取码: 6pp2