Tkinter 模块(Tk 接口)是 Python 的标准 Tk GUI 工具包的接口 .Tk 和 Tkinter 可以在大多数的 Unix 平台下使用,同样可以应用在 Windows 和 Macintosh 系统里。Tk8.0 的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中。
Tkinter 是 Python 的标准 GUI 库。Python 使用 Tkinter 可以快速的创建 GUI 应用程序。
由于 Tkinter 是内置到 python 的安装包中、只要安装好 Python 之后就能 import Tkinter 库、而且 IDLE 也是用 Tkinter 编写而成、对于简单的图形界面 Tkinter 还是能应付自如。
注意:Python3.x 版本使用的库名为 tkinter,即首写字母 T 为小写。
import tkinter
验证模块是否已安装
终端中运行命令:python -m tkinter
,运行后界面会弹出一个 tk 小窗口,表示安装成功,而且告诉你 Tcl/Tk 的版本号,通过这个版本号,你就可以参考对应的 Tcl/Tk 文档了。
创建 GUI 界面,作为根窗口:
# 创建主窗口
root = tk.Tk()
root.title("tk Root") # 设置窗口名称
root.geometry('200x200') # 设置窗口大小
# 运行
root.mainloop()
类 | 名称 | 简介 |
---|---|---|
Toplevel | 顶层 | 容器类,为其他组件提供单独容器 |
Button | 按钮 | 按钮组件 |
Canvas | 画布 | 提供绘图功能,包括:直线,矩形,椭圆,多边形,位图等 |
Checkbutton | 复选框 | 可选的复选框 |
Entry | 单行输入框 | 可输入内容 |
Frame | 容器 | 装载其它GUI组件 |
Label | 标签 | 显示不可编辑的文本或图标 |
LabelFrame | 容器 | 容器组件,类似Frame支持添加标题 |
Listbox | 列表框 | 列出多个选项,供选择 |
Menu | 菜单 | 菜单组件 |
Menubutton | 菜单按钮 | 包含菜单的按钮(下拉式,层叠式) |
OptionMeny | 菜单按钮 | Menubutton的子类,可通过按钮打开一个菜单 |
Message | 消息框 | 类似标签,但可以显示多行文本 |
PanedWindow | 分区窗口 | 该容器会被划分成多个区域,每添加一个组件占一个区域,用户可以拖动分割线改变各区域大小 |
Radiobutton | 单选钮 | 供用户点边的单选妞 |
Scale | 滑动条 | 拖动滑动块可设定起始值和结束值,可显示当前位置的精确值 |
Spinbox | 微调选择器 | 可通过该组件的向上、向下箭头选择不同的值 |
Scrollbar | 滚动条 | 为组件提供滚动功能 |
Text | 多行文本框 | 显示多行文本 |
属性说明:
width, height=宽高 font(name,size)=字体 image=图像(只支持GIF格式)
fg(foreground)=前景色 bg(background)=背景色 justify(left|center|right)=对齐方式
# 设置 label 属性
L = tk.Label(root, # 窗口
text='展示标签!', # 描述
bg='green', # 背景
borderwidth=5, # 边界宽度
relief="solid", # 指定组件 3D 效果
justify="right", # 字体对齐方式
font=('微软雅黑', 12), # 字体
width=15, height=2) # 宽高
# 放置 label 控件在窗口中的位置
L.pack(side='right') # 上top下bottom 左left右right
# 配置GIF图片方式
gifpath = r"D:\xxx\www.gif"
photo = tk.PhotoImage(file=gifpath) # 实例化图片对象
lab = tk.Label(image=photo) # 设置图片标签
lab.pack()
# 定义空字符串变量,用于标签属性中接收数据
var = tk.StringVar()
# 设置 label 标签属性
L = tk.Label(root, # 窗口
# text='展示标签!', # 描述
textvariable=var, # 接收外部传参
bg='green', # 背景
font=('微软雅黑', 12), # 字体
width=15, height=2) # 宽高
# 放置 label 位置
L.pack() # 上下 左left右right
on_func = False # 定义一个开关
# 按钮事件
def func():
global on_func
if on_func:
on_func = False
var.set('')
else:
on_func = True
var.set('要显示内容')
# 设置 button 按钮属性
B = tk.Button(root, text='按钮', width=15, height=2,
command=func) # 设置按钮事件,函数
B.pack()
组件中的属性,可以通过 Options 设置组件对应的属性,从而控制组件的各种状态。比如:宽度、高度、背景色等等。
有三种方式设置 Options 选项,在各种 GUI 组件中用法都一致。
fred = Button(width=15, height=2, bg="blue")
fred['fg'] = "red"
fred['bg'] = "blue"
config()
方式:fred.config(width=15, height=2, bg="blue")
属性名 | 简介 |
---|---|
activebackground | 指定组件处于激活状态时的背景色 |
activeforeground | 指定组件处于激活状态时的前景色 |
disabledforeground | 指定组件处于禁用状态时的前景色 |
anchor | 指定组件内的字符在组件中显示位置,选项值(N,NE,E,SE,S,SW,W,NW,CENTER) |
background | 组件正常的背景色(bg) |
foreground | 组件正常的前景色(fg) |
bitmap | 指定在组件上显示该选项指定的位图,位图的显示方式受anchor、justify影响。如果同时指定bitmap和text,那么bitmap覆盖文本;如果同时指定bitmap和image,那么image覆盖bitmap。 |
relief | 组件的3D效果,支持: raised(凸起),sunken(凹陷),flat(平坦),ridge(隆起),solid(实心),groove(凹槽) |
borderwidth | 指定组件正常显示的3D边框宽度 |
cursor | 指定光标在组件上的样式 |
command | 指定组件关联的命令方法。该方法在组件离开组件时触发 |
font | 组件上显示的文字字体 |
highlightbackground | 指定组件在高亮状态下的背景色 |
highlightcolor | 指定组件在高亮状态下的前景色 |
highlightthickness | 指定组件在高亮状态下的周围方形区域的宽度 |
state | 组件的当前状态,支持:NORMAL(正常),DISABLE(禁用) |
height | 组件的高度 |
width | 组件的宽度 |
wraplength | 对于能支持字符换行的组件,该选项指定每行显示的最大字符数,超过设定自动换行 |
image | 组件中显示的图片 |
justify | 组件内部内容对齐方式,支持(小写):LEFT(左对齐),CENTER(居中),RIGHT(右对齐) |
padx | 组件内部在水平方向上两边的空白 |
pady | 组件内部在垂直方向上两边的空白 |
takefocus | 指定组件在键盘遍历(Tab或Shift+Tab)时是否接收焦点,将选项设为1:接收焦点;设为0:不接受焦点 |
text | 组件显示的文本 |
textvariable | 指定一个变量名,组件负责显示该变量值转换得到的字符串 |
underline | 指定组件文本的第几个字符添加下划线,该选项相当于为组件绑定了快捷键 |
xscrollcommand | 通常用于将组件的水平滚动改变与水平滚动条的 set 方法关联,从而让组件的水平滚动改变传递到水平滚动条 |
yscrollcommand | 通常用于将组件的垂直滚动改变与垂直滚动条的 set 方法关联,从而让组件的垂直滚动改变传递到垂直滚动条 |
Entry 用来接收一行字符串的控件,如果用户输入的内容长度超过 Entry 控件的宽度时,文字会自动换行。
简单示例:
def login():
print('名称:'+entry1.get()) # 接收文本框的内容
labe = tk.Label(root, text="名称:")
labe.pack()
v1 = tk.StringVar() # 设置空字符串变量,属性value='可设置默认值'
# 单行文本框
# show属性可将输入的内容转为指定字符方式显示,比如输入密码
entry1 = tk.Entry(root, textvariable=v1, show='*')
entry1.pack()
v1.set('设置初始值...') # 方式二:单独设置默认值
tk.Button(root, text='发送文本中内容', command=login).pack()
主要用来显示多行文本,还可以显示网页链接、图片、HTML、CSS样式表、添加组件等等。
wrap=换行方式,word:单词换行
undo,True:开启撤销功能, False:不开启
示例:
''' Text 多行文本框 '''
tk.Label(root, text='文本框:', width=30).pack(anchor='w')
# 创建多行文本
tex = tk.Text(root, width=40, height=12)
tex.pack()
index:位置,可数字表示(行从1起,列从0起),或INSERT(开始)、END(结尾)
str:需要插入的内容
规则:不包头,包尾
tex.insert('insert', 'ABCD\nEFG') # 在第一行第0列位置插入内容
tex.insert(2.2, '12345') # 在第二行第3列位置插入内容
'''结果:
ABCD
EF12345G
'''
insert:起始位置,int类型,用1.0表示(行从1起,列从0起);
end:结尾,str类型或 int类型,用1.0表示(行从1起,列从0起);
tex.get(3.2, 3.7) # 指定范围内
tex.get(3.2, 'end') # 指定起始位置至结尾
gifpath1 = r"D:\xxxx\www.gif"
photo1 = tk.PhotoImage(file=gifpath1)
tex.image_create('end', image=photo1) # 在结尾放入图片
background, bd, bg, borderwidth, cursor,exportselection, fg, font, foreground, ighlightbackground,
highlightcolor, highlightthickness, insertbackground,insertborderwidth, insertofftime, insertontime,
insertwidth,invalidcommand, invcmd, justify, relief, selectbackground,selectborderwidth,
electforeground, show, state, takefocus,textvariable, validate, validatecommand, vcmd, width,xscrollcommand
value: 定义单选按钮返回的内容
''' 单选按钮 '''
def confirm():
messagebox.showinfo('测试', '选择的内容:' + var.get())
var = tk.StringVar()
var.set("J")
tk.Label(root, text='单选: ', width=10).pack(anchor='w')
radio1 = tk.Radiobutton(root, text='Python', value='P', variable=var)
radio2 = tk.Radiobutton(root, text='Java', value='J', variable=var)
radio1.pack(anchor='w'); radio2.pack(anchor='w')
tk.Button(root, text='确认', command=confirm).pack()
onvalue=1 # 1 表示默认选状态,0 表示不选
offvalue=0 # 未选择的返回值
def check():
if code.get() == 1 and vide.get() == 1:
messagebox.showinfo('多选', '选择:python, java')
elif vide.get() == 1:
messagebox.showinfo('多选', '选择:java')
elif code.get() == 1:
messagebox.showinfo('多选', '选择:python')
else:
messagebox.showinfo('多选', '都没选择!')
tk.Label(root, text='多选:', width=10).pack(anchor='w')
code = tk.IntVar(); vide = tk.IntVar() # 接收int类型参数
check1 = tk.Checkbutton(root, text='python', onvalue=1, offvalue=0, variable=code)
check2 = tk.Checkbutton(root, text='Java', onvalue=1, offvalue=0, variable=vide)
check1.pack(anchor='w'); check2.pack(anchor='w')
tk.Button(root, text='多选确认', command=check).pack()
activebackground, activeforeground, anchor,background, bd, bg, bitmap, borderwidth,
command, cursor,disabledforeground, fg, font, foreground, height,highlightbackground,
highlightcolor, highlightthickness, image,indicatoron, justify, offvalue, onvalue, padx, pady,
relief,selectcolor, selectimage, state, takefocus, text, textvariable,underline, variable, width, wraplength
Messagebox 用于显示弹出消息。Messagebox主要提供了7种消息提示,如:showinfo()、showerror()、showwarning()、askquestion()、askokcancel()、askyesno()、askretyrcancel()。
导入方式:
from tkinter import messagebox
消息对话框函数列表:
返回值:选择项
函数 | 说明 |
---|---|
showinfo(title, message, **options) | 消息提示框 |
showerror(title, message, **options) | 错误提示框 |
showwarning(title, message, **options) | 警告提示框 |
askquestion(title, message, **options) | 疑问提示框 |
askokcancel(title, message, **options) | 确定/取消 |
askyesno(title, message, **options) | yes/No |
askretrycancel(title, message, **options) | 重试/取消 |
简单示例:
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()
root.title("TK title")
root.geometry("500x1000+100+200")
def msg1():
messagebox.showinfo('information', 'Hi! You got a prompt.')
messagebox.showerror('error', 'Something went wrong!')
messagebox.showwarning('warning', 'accept T&C')
messagebox.askquestion('Ask Question', 'Do you want to continue?')
messagebox.askokcancel('Ok Cancel', 'Are You sure?')
messagebox.askyesno('Yes|No', 'Do you want to proceed?')
messagebox.askretrycancel('retry', 'Failed! want to try again?')
tk.Button(root, text='Click Me', command=msg1).pack(pady=50)
canvas 画布是一个矩形区域,可以放置图形、图像、组件等等。
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
# 代表父类的定义,不是父类对象
super().__init__(master)
self.master = master
self.pack()
self.createWidget()
def createWidget(self):
self.canvas = tk.Canvas(self, width=300, height=200, bg='green')
self.canvas.pack()
# 画一条直线
self.canvas.create_line(10,10,30,20,40,50)
# 画一个矩形
self.canvas.create_rectangle(50,50,100,100)
# 画一个圆
self.canvas.create_oval(50,50,100,100)
# 加图片
path = "D:\wangxin_m\selenium_py36\gui_tkinter\www.gif"
global photo
photo = tk.PhotoImage(file=path)
self.canvas.create_image(110,300, image=photo)
if __name__ == '__main__':
root = tk.Tk()
root.title('画布练习')
root.geometry('500x200+200+200')
app = Application(master=root)
root.mainloop()
一个 GUI 应用程序必然有大量的组件,tkinter提供了布局管理器帮助我们组织、管理在父组件中子组件的布局方式。提供了三种管理器:pack、grid、place。
采用表格结构组织组件;子组件的位置由行和列的单元格来确定,并且可以跨行和跨列,从而实现复杂的布局。
选项 | 说明 |
---|---|
column | 单元格的列号(从0开始) |
columnspan | 跨列 |
row | 单元格的行号(从0开始) |
rowspan | 跨行 |
ipadx,ipady | 设置子组件之间的间隔 |
padx,pady | 并列的组件之间的间隔 |
sticky | 组件紧贴所在单元格的某一角,对应对应东南西北及4个角 |
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
# 代表父类的定义,不是父类对象
super().__init__(master)
self.master = master
self.pack()
self.gridWidget()
def gridWidget(self):
self.labY = tk.Label(self, text='用户名')
self.labP = tk.Label(self, text='iPhone')
self.enrY = tk.Entry(self)
self.enrP = tk.Entry(self)
# 设置控件位置
self.labY.grid(row=0, column=0) # row=0, column=0 表示:第1行第1列位置
self.enrY.grid(row=0, column=1)
self.labP.grid(row=1, column=0)
self.enrP.grid(row=1, column=1)
tk.Button(self, text='登录').grid(row=2, column=0, sticky='w')
tk.Button(self, text='取消').grid(row=2, column=1, sticky='e')
# 跨行,多行文本框
self.text = tk.Text(self, width=28, height=3)
self.text.grid(row=3, column=0, columnspan=2)
if __name__ == '__main__':
root = tk.Tk()
root.title('画布练习')
app = Application(master=root)
root.mainloop()
计算器布局示例:
class Application(tk.Frame):
def __init__(self, master=None):
# 代表父类的定义,不是父类对象
super().__init__(master)
self.master = master
self.pack()
self.jsqWidget()
def jsqWidget(self):
btnText = (("MC", "M+", "M-", "MR"), ("C", "±", "/", "*"),
(7,8,9,"-"),(4,5,6,"+"),(1,2,3,"="), (0, ".") )
# 显示框,第一行
tk.Entry(self).grid(row=0, column=0, columnspan=4, pady=10)
# 按钮控件布局
for rindx, r in enumerate(btnText):
for cindx, c in enumerate(r):
if c == "=":
but_d = tk.Button(self, text=c, width=3)
but_d.grid(row=rindx+1, column=cindx, rowspan=2, sticky='nsWE')
elif c == 0:
but_0 = tk.Button(self, text=c, width=3)
but_0.grid(row=rindx+1, column=cindx, columnspan=2, sticky='nsWE')
elif c == '.':
but_d = tk.Button(self, text=c, width=3)
but_d.grid(row=rindx+1, column=cindx+1, sticky='nsWE')
else:
tk.Button(self, text=c, width=3).grid(row=rindx+1, column=cindx, sticky='nsWE')
按照组件的创建顺序将子组件添加到父组件中,按照“垂直”或者“水平”的方向自然排序。默认在父组件中自顶向下垂直添加组件。
选项 | 说明 |
---|---|
expand | 当值为"YES"时,side选项无效,组件显示在父组件中心位置,若fill选项为"both",则填充父组件的剩余空间;'yes’或自然数、'no’或0(默认) |
fill | 填充x或y方向的空间,x=水平,y=垂直,both=两边填充;当属性side='top’或’bottom’时,填充x方向;当属性side='left’或’right’时,填充y方向;当expand选项为’yes’时,填充父组件的剩余空间 |
ipadx,ipady | 设置子组件之间的间隔 |
padx,pady | 与之并列的组件之间的间隔 |
side | 定义停靠父组件的那个位置(left’、‘right’、‘top’、‘bottom’) |
before | 将本组件于所选组件对象之前pack,类似于先创建本组件选定的组件 |
after | 将本组件与选择组件对象之后pack,类似先创建选定组件后再创建本组件 |
anchor | 对齐方式(n,s,w,e,nw,sw,se,ne,center) |
in_ | 将本组件所选组件对象的子组件,类似于指定本组件的masster为选定组件 |
示例:
root = tk.Tk()
root.title('画布练习')
root.geometry("700x220")
# Frame 画布区域,用于放置子组件
f1 = tk.Frame(root, bg='blue'); f1.pack()
f2 = tk.Frame(root, bg='yellow'); f2.pack()
btnText = ["A", "B", "C", "D"]
for t in btnText:
tk.Button(f1, text=t).pack(side='left', padx="10")
for i in range(1, 10):
tk.Label(f2, text=i, width=2, height=3, borderwidth=1, relief="raised",
bg="red").pack(side="left", padx=4)
root.mainloop()
通过坐标精确控制组件的位置,适用于一些布局更加灵活的场景。
选项 | 说明 | 取值范围 |
---|---|---|
x,y | 组件左上角的绝对坐标(相对于窗口) | 非负整数,x和y选项用于设置偏移(像素),如果同时设置relx(rely) 和x(y),那么place将优先计算relx和rely,然后在实现x和y指定的偏移值 |
relx,rely | 组件左上角的坐标(相对于父窗口) | 相对父组件位置,0为最左边,0.5为中间,1位最右边 |
width,height | 组件的宽度和高度 | 正整数 |
relwidth,relheight | 组件的宽度和高度(相对于父窗口) | 与relx,rely类似,但是相对于父组件的尺寸 |
anchor | 对齐方式 | n,s,w,e,nw,sw,se,ne,center |
示例:
root = tk.Tk()
root.title('画布练习')
root.geometry("500x300")
# Frame 画布区域,用于放置子组件
f1 = tk.Frame(root, width=200, height=200, bg='blue'); f1.place(x=20, y=20)
tk.Button(root, text='root位置').place(relx=0.1, relwidth=0.3, relheight=0.2)
tk.Button(f1, text='f1位置').place(relx=0.2, rely=0.5)
root.mainloop()
一个 GUI 应用整个生命周期都处在一个消息循环(eventloop)中。它等待事件的发生,并作出相应的处理。
tkinter 提供了用以处理相关事件的机制,处理函数可被绑定给各个空间的各个事件。
widget.bind(event,handler)
如果相关事件发生, handler 函数会触发,事件对象 event 会传递给 handler 函数。
event 代表事件
handler 代表事件要处理的方式(函数)
代码 | 说明 |
---|---|
鼠标左键按下。1=左键,2=中键,3=右键 | |
鼠标左键释放。 1=左键,2=中键,3=右键 | |
鼠标左键移动 | |
双击左键 | |
鼠标指针进入某一组件区域 | |
鼠标指针离开某一组件区域 | |
滚动滑轮 | |
响应按下的任意键 | |
按下 a 键,a可自定义(a-zA-Z) | |
释放 a 键,a可自定义其它小写字母 | |
同时按下 alt和a ;alt可用Ctrl和shift代替 | |
快速双击a | |
Ctrl和V键同时按下,V可以自定义 |
名称 | 说明 |
---|---|
char | 按键字符,仅对键盘事件有效 |
Keycode | 按键编码,仅对键盘事件有效 |
Keysym | 按键名称,仅对键盘事件有效。比如按下 a 键:char:a、 Keycode:65、Keysym:a |
num | 鼠标按键,仅对鼠标事件有效 |
type | 所触发的事件类型 |
widget | 引起事件的组件 |
width,height | 组件改变后的大小,仅Configure有效 |
x,y | 鼠标当前位置,相对于父容器 |
x_root,y_root | 鼠标当前位置,相对于整个屏幕 |
示例:
import tkinter as tk
# 创建主窗口
root = tk.Tk()
root.title("TK title")
root.geometry("500x500+10+20")
''' 鼠标和键盘事件 '''
C1 = tk.Canvas(root, width=200, height=200, bg='green')
C1.pack()
def mouseT(event):
print("鼠标左键单击位置(父容器):{},{}".format(event.x,event.y))
print("鼠标左键单击位置(屏幕):{},{}".format(event.x_root,event.y_root))
print("事件绑定的组件:{}".format(event.widget))
def dragT(event):
print("鼠标移动点位置:", event.x, event.y, event.x+1, event.y+1)
C1.create_oval(event.x, event.y, event.x+10, event.y+10)
def keyboardT(event):
'''响应按下的任意键'''
print("键的keyconde:{}, 键的char:{}, 键的keysym:{}".format(event.keycode, event.char, event.keysym))
def press_a_T(event):
print("按下a键")
def release_a_T(event):
print("释放a键")
# 对 C1 画布范围内有效
C1.bind("", mouseT)
C1.bind("", dragT)
# 对整个GUI界面有效
root.bind("", keyboardT)
# 只针对小写字母 a 有效
root.bind("", press_a_T)
root.bind("", release_a_T)
root.mainloop() # 运行GUI
组件对象绑定
command
属性绑定(适合不需要获取event对象)Button(root, text='登录', command=login)
bind()
方法绑定(合适需要获取event对象)c1 = tkinter.Canvas()
c1.bind("", drawLine)
组件类的绑定
调用对象的 bind_class
函数,将该组件类型的所有组件绑定事件:w.bind_class('Widget', 'event', eventhanler)
w 代表控件
Widget=控件,event=事件,eventhanler=调用函数
# 比如给GUI上的所有按钮绑定事件
btn01.bind_class("Button", "",func)
示例:
import tkinter as tk
root = tk.Tk()
root.title("TK title")
def mouseT(event):
print("bind()方式绑定,可以获取event对象:{}".format(event.widget))
def mouseT1(a,b):
print("command方式绑定,不能获取event对象:a={},b={}".format(a,b))
def mouset2(event):
print("右键单击事件,给所有的按钮绑定事件:{}".format(event.widget))
btn1 = tk.Button(root, text="测试bind()事件绑定")
btn1.pack()
btn1.bind("", mouseT) # bind方式绑定
btn2 = tk.Button(root, text="测试command绑定", command=lambda :mouseT1('AA', "BB"))
btn2.pack()
# 绑定给所有的按钮右键事件
btn2.bind_class("Button", "", mouset2)
root.mainloop() # 运行GUI
下拉选项,用来做多选一,选中的项在顶部显示。
示例:
import tkinter as tk
root = tk.Tk()
root.title("TK title")
strvar = tk.StringVar()
strvar.set('编程') # 设置默认值
om = tk.OptionMenu(root, strvar, 'java', 'python', 'php')
om['width'] = 10
om.pack()
root.mainloop() # 运行GUI
用于在指定的数值区间,通过滑块的移动选择值。
相关属性:
activebackground, background, bigincrement, bd,bg, borderwidth, command, cursor, digits, fg, font, foreground, from,highlightbackground, highlightcolor, highlightthickness, label,
length, orient, relief, repeatdelay, repeatinterval, resolution,showvalue, sliderlength, liderrelief, state, takefocus, tickinterval, to, troughcolor, variable, width
示例:(默认为垂直方向)
import tkinter as tk
root = tk.Tk()
root.title("TK title")
def test(value):
print("滑块的值:", value)
# 重新设置按钮字体的大小,滑块控制
lab.config(font=('宋体', value))
sca = tk.Scale(root, from_=5, to=50, length=200, tickinterval=5, command=test, orient='horizontal') # 滑块方式,horizontal=水平
sca.pack()
lab = tk.Label(root, text='测试滑块', width=10, height=1, fg='white', bg='black', font=('宋体', 5))
lab.pack()
root.mainloop() # 运行GUI
可以帮助我们设置背景色、前景色、画笔色、字体颜色等等。
导入方式:
from tkinter.colorchooser import askcolor
示例:
import tkinter as tk
from tkinter.colorchooser import askcolor
root = tk.Tk()
root.title("TK title")
def test():
# 创建颜色选择器,color=默认颜色
ask = askcolor(color='red', title='颜色标题')
print("背景色:", ask) # 返回是 RGB 值
root.config(bg=ask[1]) # 修改背景颜色
tk.Button(root, text='选择', command=test).pack()
root.mainloop() # 运行GUI
可以帮助我们实现可视化的操作目录、文件。最后将文件、目录的信息传入到程序中。
导入方式:
from tkinter.filedialog import askopenfilename
常用函数:
函数名 | 对话框 | 说明 |
---|---|---|
askopenfilename(**options) | 文件对话框 | 返回打开的文件名 |
askopenfilenames(**options) | 文件对话框 | 返回打开的多个文件名列表 |
askopenfile(**options) | 文件对话框 | 返回打开文件对象 |
askopenfiles(**options) | 文件对话框 | 返回打开的文件对象的列表 |
askdirectory(**options) | 目录对话框 | 返回目录名 |
asksaveasfile(**options) | 保存对话框 | 返回保存的文件对象 |
asksaveasfilename(**options) | 保存对话框 | 返回保存的文件名 |
options 常用的值:
参数 | 说明 |
---|---|
defaultextension | 默认后缀:.xxx 用户没有输入则自动添加 |
filetypes=[(label1,pattern1),(label2,pattern2)] | 文件显示过滤器 |
initaldir | 初始目录 |
initalfile | 初始目录 |
parent | 父窗口,默认根窗口 |
title | 窗口标题 |
选择文件示例:
import tkinter as tk
from tkinter.filedialog import askopenfilename
root = tk.Tk()
root.title("TK title")
# initialdir=默认打开目录路径,filetypes=文件过滤
def test():
ask = askopenfilename(title='上传文件', initialdir='d:\\', filetypes=[('PY文件','.py')])
show["text"] = ask
vv.set(ask) # 将选择的文件绝对路径,输入到文本框中
show = tk.Button(root, text='选择文件', command=test)
show.pack()
vv = tk.StringVar()
e = tk.Entry(root, textvariable=vv, width=50)
e.pack()
root.mainloop() # 运行GUI
直接读取文件的内容示例:
import tkinter as tk
from tkinter.filedialog import askopenfile
root = tk.Tk()
root.title("TK title")
def test():
with askopenfile(title='上传文件', initialdir="d:\\", filetypes=[('文件', '.txt')]) as f:
show.delete(1.0, 'end') # 删除文本框中之前的内容
show.insert('insert', f.read()) # 将读取到的文件内容写入到文本框中
tk.Button(root, text='选择文件', command=test).pack()
show = tk.Text(root, width=60, height=20)
show.pack()
root.mainloop() # 运行GUI
simpledialog(简单对话框)包含如下常用函数:
函数 | 说明 |
---|---|
askfloat(title,prompt,**kw) | 输入并返回浮点数 |
askinteger(title,prompt,**kw) | 输入并返回整数 |
askstring(title,prompt,**kw) | 输入并返回字符串 |
title 代表窗口标题;prompt 是提示描述内容;
kw 代表不定长参数,可以为:initialvalue(初始值), minvalue(最小值), maxvalue(最大值)
示例:
import tkinter as tk
from tkinter.simpledialog import askfloat, askinteger,askstring
root = tk.Tk()
root.title("TK title")
def integer_t(): # 其他两个用法一样
integer = askinteger(title='整数', prompt='请输入整数:', initialvalue=10, minvalue=0, maxvalue=100)
show.insert('end', integer)
But = tk.Button(root, text='输入整数', command=integer_t)
But.pack()
show = tk.Text(root, width=60, height=20)
show.pack()
root.mainloop() # 运行GUI
主菜单通常位于 GUI 程序的上方位置。
导入方式:
from tkinter.filedialog import *
menubar = tk.Menu(master=root)
menuFile = tk.Menu(menubar)
menubar.add_cascade(label="文件(F)", menu=menuFile)
menuEdit = tk.Menu(menubar)
menubar.add_cascade(label="编辑(E)", menu=menuEdit)
menuFile.add_command(label="新建", accelerator="ctrl+n", command=self.newfile)
menuFile.add_command(label="打开", accelerator="ctrl+o", command=self.openfile)
menuEdit.add_command(label="查找", accelerator="ctrl+f", command=self.test)
menuEdit.add_command(label="删除", accelerator="ctrl+d", command=self.test)
root["menu"] = menubar
创建菜单示例:
# ''' 创建主菜单 '''
menubar = tk.Menu(root)
# ''' 创建子菜单 '''
menuFile = tk.Menu(menubar)
menuEdit = tk.Menu(menubar)
menuHelp = tk.Menu(menubar)
# '''将子菜单加入到主菜单栏'''
# label=名称;menu=对应的菜单
menubar.add_cascade(label="文件(F)", menu=menuFile)
menubar.add_cascade(label="编辑(E)", menu=menuEdit)
menubar.add_cascade(label="帮助(H)", menu=menuHelp)
# '''添加文件菜中的子菜单'''
# label=名称;accelerator=快捷键方式描述;command=选项执行事件
menuFile.add_command(label="新建", accelerator="ctrl+n", command=self.newfile)
menuFile.add_command(label="打开", accelerator="ctrl+o", command=self.openfile)
menuFile.add_command(label="保存", accelerator="ctrl+s", command=self.savefile)
menuFile.add_separator() # 添加分割线
menuFile.add_command(label="退出", accelerator="ctrl+q", command=self.exit)
# '''添加编辑菜中的子菜单'''
menuEdit.add_command(label="查找", accelerator="ctrl+f", command=self.test)
menuEdit.add_command(label="删除", accelerator="ctrl+d", command=self.test)
# '''添加帮助菜中的子菜单'''
menuHelp.add_command(label="帮助", accelerator="ctrl+h", command=self.test)
# ''' 将主菜单添加到 root 主窗口 '''
root["menu"] = menubar
contextMenu = tk.Menu(root)
contextMenu.add_command(label="背景颜色", command=openAskcolor)
def openAskcolor():
color = askcolor(color='red', title="选择背景颜色", )
textpad.config(bg=color[1])
def createContextMenu(event):
# 右键菜单,在鼠标右键时显示菜单
contextMenu.post(event.x_root, event.y_root)
root.bind("" , createContextMenu)
示例:
# 文本编辑区
self.textpad = Text(root, width=60, height=30)
self.textpad.pack()
# 创建鼠标右键上下菜单
self.contextMenu = tk.Menu(root)
self.contextMenu.add_command(label="背景颜色", command=self.openAskcolor)
# 右键绑定事件
root.bind("" , self.createContextMenu)
def openAskcolor(self):
color = askcolor(color='red', title="选择背景颜色", )
self.textpad.config(bg=color[1]) # 修改背景颜色
简单记事本案例:
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter.ttk import Scrollbar, Checkbutton, Label, Button
import os
class NotePad(tk.Tk):
def __init__(self):
super().__init__()
self.set_window()
self.create_menu_bar()
self.create_body()
def set_window(self):
'''设置窗口参数'''
self.title("记事本")
max_width, max_height = self.maxsize() # 屏幕的大小
align_center = "800x600+%d+%d" % ((max_width-800)/2, (max_height-600)/2)
self.geometry(align_center)
self.iconbitmap("www.gif") # 图标
def create_menu_bar(self):
''' 创建菜单对象 '''
menu_bar = tk.Menu(self)
# 添加菜单项目 tearoff=去掉默认分隔符
File_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="文件", menu=File_menu) # 菜单名称
File_menu.add_command(label="打开", accelerator="ctrl+o", command=self.open_file) # 下拉菜单名称
File_menu.add_separator()
File_menu.add_command(label="退出", accelerator="Ait+F4", command=self.quit) # 二级菜单
Editor_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="编辑", menu=Editor_menu) # 菜单名称
Editor_menu.add_command(label="查找", accelerator="Ctrl+F", command=self.find_text_dialog)
View_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="视图", menu=View_menu) # 菜单名称
# 显示行号
self.is_show_line = tk.IntVar()
self.is_show_line.set(1) # 默认从1开始
View_menu.add_checkbutton(label="显示行号", onvalue=0, offvalue=1,
variable=self.is_show_line, command=self.update_line_num)
# 高亮当前行
self.is_height_line = tk.IntVar()
View_menu.add_checkbutton(label="高亮当前行", variable=self.is_height_line, command=self.toggle_row)
# 主题,下拉菜单嵌套菜单
themes_menu = tk.Menu(menu_bar, tearoff=0)
View_menu.add_cascade(label="主题", menu=themes_menu) # 菜单名称
themes_menu.add_command(label="主题1", accelerator="a+b", command="")
About_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="关于", menu=About_menu) # 菜单名称
About_menu.add_command(label="", command="")
# 将设置的菜单项目加的菜单栏中
self.config(menu=menu_bar)
def create_body(self):
''' 左边=行号,中间编辑区,右边=滚动条 '''
# 行号区域
self.line_num_bar = tk.Text(self, width=2, padx=1, takefocus=0, border=0,
background="#AAADAA", state="disable")
self.line_num_bar.pack(side="left", fill="y")
# 文本编辑区
self.context_text = tk.Text(self, wrap="word", undo=True)
self.context_text.pack(fill="both", expand='yes')
# 热键绑定-注意按键参数会传入到指定事件中
self.context_text.bind("" , self.open_file)
self.context_text.bind("" , self.update_line_num)
self.context_text.bind('' , self.toggle_row)
# 设置文本输入区域
self.context_text.tag_config("active_line", background="#F7E3AD")
# 垂直滚动条
scroll_bar = Scrollbar(self.context_text) # 将滚动条与文本框关联
scroll_bar['command'] = self.context_text.yview # 将滚动条与文本框的Y轴关联
self.context_text["yscrollcommand"] = scroll_bar.set # 将文本框的Y轴滚动交给滚动条处理
scroll_bar.pack(side="right", fill="y")
def open_file(self, event=None):
''' 打开文件 '''
input_fiel = filedialog.askopenfilename(filetype=[("文本类型", ".txt"), ("所有类型", "*.*")])
if input_fiel:
# 不同状态,修改标题显示
self.title("{}**".format(os.path.basename(input_fiel)))
self.context_text.delete(1.0, "end")
with open(input_fiel, "r") as f:
self.context_text.insert(1.0, f.read())
else:
messagebox.showerror("错误", "打开文件失败!")
def update_line_num(self, event=None):
''' 行号处理 '''
# self.is_show_line.get 0:代表选中, 1:代表未选中
if self.is_show_line.get() == 0:
# 获取所有的行
row, col = self.context_text.index("end").split(".")
# 列举每行的行号
line_num_content = "\n".join([str(i) for i in range(1, int(row))])
self.line_num_bar.config(state="normal")
self.line_num_bar.delete(1.0, "end")
self.line_num_bar.insert(1.0, line_num_content)
self.line_num_bar.config(state="disable")
else:
self.line_num_bar.config(state="normal")
self.line_num_bar.delete(1.0, "end")
self.line_num_bar.config(state="disable")
def toggle_row(self, event=None):
''' 高亮行 '''
if self.is_height_line.get():
self.context_text.tag_remove("active_line", 1.0, "end")
# 设置高亮
self.context_text.tag_add("active_line", "insert linestart", "insert lineend+1c")
# 通过递归方式进行处理 或 鼠标左键事件
# self.context_text.after(200, self.toggle_row)
else:
self.context_text.tag_remove("active_line", 1.0, "end")
def find_text_dialog(self):
''' 查找对话框 '''
# 查找对话框大小设置
search_dialog = tk.Toplevel(self)
search_dialog.title("查找文本")
max_width, max_height = self.maxsize()
align_center = "300x80+{}+{}".format(int((max_width-300)/2), int((max_height-80)/2))
search_dialog.geometry(align_center)
search_dialog.resizable(False, False)
Label(search_dialog, text="查找全部").grid(row=0, column=0, sticky="e")
search_text = tk.Entry(search_dialog, width=25)
search_text.grid(row=0, column=1, padx=2, pady=2, sticky="we")
search_text.focus_set()
# 忽略大小写
ignore_case_value = tk.IntVar()
Checkbutton(search_dialog, text="忽略大小写", variable=ignore_case_value).grid(
row=1, column=1, padx=2, pady=2, sticky="e")
Button(search_dialog, text="查找", command=lambda: self.search_result(search_text.get(),
ignore_case_value.get(), search_dialog, search_text)).grid(row=0, column=2,
sticky='w'+"e", padx=10, pady=1)
# 关闭
def colse_search_dialog():
self.context_text.tag_remove('match', 1.0, 'end')
search_dialog.destroy()
search_dialog.protocol('WM_DELETE_WINDOW', colse_search_dialog)
return "break"
def search_result(self, text, ignore_case, search_dialog, search_box):
'''
:param text: 要查找的文本内容
:param ignore_case: 是否忽略大小写
:param search_dialog: 查找的目标窗体
:param search_box: 查找结果焦点
'''
# 清楚匹配内容
self.context_text.tag_remove('match', 1.0, 'end')
matches_found = 0
if text:
start_pos = 1.0
while True:
start_pos = self.context_text.search(text, start_pos, nocase=ignore_case, stopindex='end')
if not start_pos:
break
end_pos = "{}+{}c".format(start_pos, len(text))
self.context_text.tag_add('match', start_pos, end_pos)
matches_found += 1
start_pos = end_pos
self.context_text.tag_config('match', foreground="red", background="yellow")
search_box.focus_set()
search_dialog.title("发现了 %d 个匹配项" % matches_found)
if __name__ == '__main__':
app = NotePad()
app.mainloop()