tkinter模块
以下内容大部份出自:Python GUI开发手册(化学工业出版社)
一、创建一个空白窗口:
from tkinter import * win = Tk() win.title("My GUI") win.mainloop()
二、设置窗口属性:
1、设置窗口样式的相关方法及其含义:
title() 设置窗口标题
geoemetry("widthxheight") 设置窗口的大小及位置,单位为pilex
maxsize() 窗口的最大尺寸
minsize() 窗口的最小尺寸
configure(bg=color) 为窗口添加背景颜色
resizable(True,True) 设置窗口大小是否可以更改,第一个表示是否可以更改宽度,第二个是高度,默认True
state("zoomed") 将窗口最大化
iconify() 将窗口最小化
iconbitmap() 设置窗口的默认图标
示例:给窗口添加标题:
from tkinter import * win = Tk() win.title("My GUI") txt = Label(win,text="\n\ngame over\n\n").pack() win.mainloop()
三、设置窗口位置:
from tkinter import * win = Tk() win.title("My GUI") win.configure(bg="#a7ea90") #窗口背景颜色 winw = 300 #窗口宽度 winh = 220 #窗口高度 scrw = win.winfo_screenwidth() #获取屏幕宽度 scrh = win.winfo_screenheight() #获取屏幕高度 x = (scrw-winw)/2 #计算窗口的水平位置 y = (scrh-winh)/2 #计算窗口的垂直位置 win.geometry("%dx%d+%d+%d" %(winw,winh,x,y)) #设置窗口大小和位置 str = "\n\n登高\n\n风急天高猿啸哀,渚清沙白鸟飞回。\n\n无边落木萧萧下,不尽长江滚滚来。\n\n万里悲秋常作客,百年多病独登台。\n\n艰难苦恨繁霜鬓,潦倒新停浊酒杯。" txt = Label(win,text=str,fg="red",bg="#a7ea90").pack() win.mainloop()
四、tkinter组件分类:
1、文件类组件:
Label:标签组件。主要用于显示文本,添加提示信息
Entry:单行文本组件。只能添加单行文本
Spinbox:输入组件。可以理解为列表菜单与单行文本框的组合体,因为该组件既可以输入内容,也可以直接从现有的选项中选择值
Scale:数字范围组件。可以使用户拖动滑块选择数值,类似于HTML5表单中的range
2、按钮类组件:
Button:按钮组件
Radiobutton:单选组件
Checkbutton:复选框组件
3、选择列表类组件:
Listbox:列表框组件
Scrollbar:滚动条组件
OptionMenu:下拉列表
Combobox:组合框
4、容器类组件:
Frame:框架组件。用于将相关的组件放置在一起,以便于管理
LabelFrame:标签框架组件。将相关组件放置在一起,并给它们一个特定的名称
Toplevel:顶层窗口。重新打开一个新窗口,该窗口显示在根窗口的上方
PanelWindow:窗口布局管理。通过该组件可以手动修改其子组件的大小
Notebook:选项卡。选择不同的内容,窗口中可显示对应的内容
5、会话类组件:
Message:消息框。为用户显示一些短消息,与Label类似,但比Label更灵活
Messagebox:会话框。该组件提供了8种不同场景的会话框
6、菜单类组件:
Menu:菜单组件。可以为窗口添加菜单项以及二级菜单
Toolbar:工具栏。为窗口添加工具栏
Treeview:树菜单
7、进度条组件:
Progressbar:添加进度条
五、虽然tkinter模块中每个组件都有各自的属性,但有些属性是各组件通用的:
foreground或fg:设置组件中文字的颜色
background或bg:设置组件的背景颜色
width:设置组件的宽度
height:设置组件高度
anchor:文字在组件内输出的位置,默认为center
padx:组件的水平间距
pady:组件的垂直间距
font:组件的文字样式
relief:组件的边框样式,主要有:solid,raised,sunken,flat,groove,ridge
cursor:鼠标悬停在组件上时的样式
示例:
from tkinter import * win = Tk() win.title("My GUI") win.configure(bg="#a7ea90") #窗口背景颜色 winw = 300 #窗口宽度 winh = 220 #窗口高度 scrw = win.winfo_screenwidth() #获取屏幕宽度 scrh = win.winfo_screenheight() #获取屏幕高度 x = (scrw-winw)/2 #计算窗口的水平位置 y = (scrh-winh)/2 #计算窗口的垂直位置 win.geometry("%dx%d+%d+%d" %(winw,winh,x,y)) #设置窗口大小和位置 str = "\n\n登高\n\n风急天高猿啸哀,渚清沙白鸟飞回。\n\n无边落木萧萧下,不尽长江滚滚来。\n\n万里悲秋常作客,百年多病独登台。\n\n艰难苦恨繁霜鬓,潦倒新停浊酒杯。" txt = Label(win,text=str,fg="red",bg="#a7ea90",width=260,height=260,anchor="nw").pack() #anchor位置参数说明: #nw:左上角;w:左中间;sw:左下角;n:上中间;s:下中间;ne:右上角;e:右中间;se:右下角 win.mainloop()
font属性的参数及含义:
family:设置字体,例如:Times New Roman
size:设置字号,单位px
weight:设置文字粗细,如bold
slant:设置斜体,如italic
underline:添加下划线,值为True或False
overstrike:添加删除线,值为True或False
示例1:
from tkinter import * win = Tk() win.title("My GUI") win.configure(bg="#a7ea90") #窗口背景颜色 winw = 300 #窗口宽度 winh = 220 #窗口高度 scrw = win.winfo_screenwidth() #获取屏幕宽度 scrh = win.winfo_screenheight() #获取屏幕高度 x = (scrw-winw)/2 #计算窗口的水平位置 y = (scrh-winh)/2 #计算窗口的垂直位置 win.geometry("%dx%d+%d+%d" %(winw,winh,x,y)) #设置窗口大小和位置 str = "\n\n登高\n\n风急天高猿啸哀,渚清沙白鸟飞回。\n\n无边落木萧萧下,不尽长江滚滚来。\n\n万里悲秋常作客,百年多病独登台。\n\n艰难苦恨繁霜鬓,潦倒新停浊酒杯。" txt = Label(win,text=str,fg="red",bg="#C3DEEF",font=("华文新魏",16,"bold","italic","underline","overstrike"),padx=200,pady=10).pack() win.mainloop()
示例2:
from tkinter import * win = Tk() win.title("My GUI") win.configure(bg="#a7ea90") #窗口背景颜色 winw = 300 #窗口宽度 winh = 220 #窗口高度 scrw = win.winfo_screenwidth() #获取屏幕宽度 scrh = win.winfo_screenheight() #获取屏幕高度 x = (scrw-winw)/2 #计算窗口的水平位置 y = (scrh-winh)/2 #计算窗口的垂直位置 win.geometry("%dx%d+%d+%d" %(winw,winh,x,y)) #设置窗口大小和位置 str = "\n\n登高\n\n风急天高猿啸哀,渚清沙白鸟飞回。\n\n无边落木萧萧下,不尽长江滚滚来。\n\n万里悲秋常作客,百年多病独登台。\n\n艰难苦恨繁霜鬓,潦倒新停浊酒杯。" txt = Label(win,text=str,fg="red",bg="#C3DEEF",relief="groove",cursor="spider") txt.pack(padx=260,pady=260,side=LEFT) win.mainloop()
六、tkinter布局管理
1、pack()方法。它是常用的一种布局方式,其参数及含义如下:
side:设置组件水平展示或垂直展示,主要有四个属性值:
top:指组件从上到下依次排列,默认值
bottom:指组件从下到上依次排列
left:指组件从左到右依次排列
right:指组件从右到左依次排列
padx:设置组件距离窗口的水平距离
pady设置组件距离窗口的垂直距离
ipadx:设置组件内的文字距离组件边界的水平距离
ipady:设置组件内的文字距离组件边界的垂直距离
fill:设置组件填充所在的空白空间的方式,主要有四个属性值:
x:表示完全填充水平方向的空白空间
y:表示完全填充垂直方向的空白空间
both:表示水平和垂直方向的空白空间都完全填充
none:表示不填充空白空间,默认值
expand:设置组件是否完全填充其余空间(父容器的额外空间),其值为True(1)或False(0)
anchor:设置组件在窗口中的位置,其值如下:
nw:左上角;w:左中间;sw:左下角;n:上中间;s:下中间;ne:右上角;e:右中间;se:右下角
before:设置该组件应该位于指定组件的前面
after:设置该组件应该位于指定组件的后面
示例1:
from tkinter import * win = Tk() txt1 = "春风吹又生" txt2 = "夏浅蝉未多" txt3 = "秋到天空阔" txt4 = "冬钓寒江雪" Label(win,text=txt1,bg="#F5DFCC").pack(side="top",padx=20,pady=5,ipadx=10,ipady=5,fill="both") Label(win,text=txt2,bg="#EDB584").pack(side="top",padx=20,pady=5,ipadx=10,ipady=5) Label(win,text=txt3,bg="#EF994C").pack(side="top",padx=20,pady=5,ipadx=10,ipady=5) Label(win,text=txt4,bg="#A7EA90").pack(side="top",padx=20,pady=5,ipadx=10,ipady=5,fill="both") win.mainloop()
示例2:
from tkinter import * win = Tk() txt = "野火烧不尽,春风吹又生" Label(win,text=txt,bg="#E6F5C8",fg="red",font=14).pack(side="top",fill="x",expand=1,anchor="nw") win.mainloop()
示例3:
from tkinter import * win = Tk() win.geometry("350x150") #设置窗口大小 win.title("退出窗口提示") win.resizable(False,False) #不可更改窗口大小 txt1 = Label(win,text="确定退出本窗口吗?") txt2 = Label(win,text="果断退出",bg="#c1ffc1") txt3 = Label(win,text="我再想想",bg="#cdb5cd") txt1.pack(fill="x",padx=20) txt2.pack(side="right",anchor="se",padx=10,pady=20,ipadx=6) txt3.pack(side="right",anchor="se",padx=10,pady=20,ipadx=6) win.mainloop()
示例4:
from tkinter import * win = Tk() win.title("动力象棋") txt1 = Label(win,text="象吃狮",bg="#f1c5c5",font=14) txt4 = Label(win,text="豹吃狼",bg="#f1c5c5",font=14) txt3 = Label(win,text="虎吃豹",bg="#cdb5cd",font=14) txt2 = Label(win,text="狮吃虎",bg="#c1ffc1",font=14) txt6 = Label(win,text="狗吃猫",bg="#cdb5cd",font=14) txt7 = Label(win,text="猫吃鼠",bg="#f1c5c5",font=14) txt5 = Label(win,text="狼吃狗",bg="#c1ffc1",font=14) txt8 = Label(win,text="鼠吃象",bg="#c1ffc1",font=14) txt1.pack(side="left",padx=10,ipadx=6,fill="y",expand=1) #将txt2放在txt1前面 txt2.pack(side="left",padx=10,ipadx=6,fill="y",expand=1,before=txt1) txt3.pack(side="left",padx=10,ipadx=6,fill="y",expand=1,before=txt2) txt4.pack(side="left",padx=10,ipadx=6,fill="y",expand=1,before=txt3) txt5.pack(side="left",padx=10,ipadx=6,fill="y",expand=1,before=txt4) txt6.pack(side="left",padx=10,ipadx=6,fill="y",expand=1,before=txt5) txt7.pack(side="left",padx=10,ipadx=6,fill="y",expand=1,before=txt6) txt8.pack(side="left",padx=10,ipadx=6,fill="y",expand=1,before=txt7) win.mainloop()
2、grid()方法。网格布局,使用row定义组件所在的行,使用column定义组件所在的列,其相关参数及其含义如下:
row:组件所在行,从0开始
column:组件所在列,从0开始
rowspan:组件横向合并的行数
columnspan:组件纵向合并的行数
sticky:组件填充所分配空间空白区域的方式,和anchor类似,不过它只有4个可选的参数:
N:上对齐
S:下对齐
W:左对齐
E:右对齐
也可以组合使用:
N+S:拉长组件高度,使组件的顶端和底端对齐
N+S+E:拉长组件高度,使组件的顶端和底端对齐,同时切齐右边
N+S+W:拉长组件高度,使组件的顶端和底端对齐,同时切齐左边
E+W:拉长组件宽度,使组件的左边和右边对齐
N+S+E+W:拉长组件高度,使组件的顶端和底端对齐,同时切齐左边和右边
padx,pady:组件距离窗口边界的水平方向及垂直方向的距离
示例1:
from tkinter import * win = Tk() win.title("乘法口诀") Label(win,text="1 * 1=1",bg="#E0FFFF").grid(row=0,column=0,padx=10) Label(win,text="1 * 2=2",bg="#E0FFFF").grid(row=1,column=0,padx=10) Label(win,text="1 * 3=3",bg="#E0FFFF").grid(row=2,column=0,padx=10) Label(win,text="1 * 4=4",bg="#E0FFFF").grid(row=3,column=0,padx=10) Label(win,text="2 * 2=4",bg="#EEA9B8").grid(row=1,column=1,padx=10) Label(win,text="2 * 3=6",bg="#EEA9B8").grid(row=2,column=1,padx=10) Label(win,text="2 * 4=8",bg="#EEA9B8").grid(row=3,column=1,padx=10) Label(win,text="3 * 3=9",bg="#F08080").grid(row=2,column=2,padx=10) Label(win,text="3 * 4=12",bg="#F08080").grid(row=3,column=2,padx=10) Label(win,text="4 * 4=16",bg="#FFE1FF").grid(row=3,column=3,padx=10) win.mainloop()
合并网格示例:
from tkinter import * win = Tk() Label(win,text="横向合并4格",width=15,height=1,relief="groove",bg="#EDE19A").grid(row=0,column=0,columnspan=4,sticky="w") Label(win,text="横向合并2格",width=15,height=1,relief="groove",bg="#EDBE9A").grid(row=1,column=0,columnspan=2,sticky="W") Label(win,text="横向合并2格",width=15,height=1,relief="groove",bg="#EDBE9A").grid(row=1,column=1,columnspan=2,sticky="W") Label(win,text="不合并",width=15,height=1,relief="groove",bg="#E5AEAE").grid(row=2,column=0) Label(win,text="不合并",width=15,height=1,relief="groove",bg="#E5AEAE").grid(row=2,column=1) Label(win,text="不合并",width=15,height=1,relief="groove",bg="#E5AEAE").grid(row=2,column=2) Label(win,text="不合并",width=15,height=1,relief="groove",bg="#E5AEAE").grid(row=2,column=3) win.mainloop()
3、rowconfigure()和columnconfigure()方法设置组件的缩放比例:
tkinter模块添加的窗口默认情况下都可以通过鼠标拖动改变大小的,而当窗口大小改变时,可以通过rowconfigure()和columnconfigure()方法改变某行或某列组件所占空间随窗口缩放的比例。需要注意的是,两个方法是设置在父容器上的,并不是设置在组件上的。用法如下:
rowconfigure(0,weight=1)
columnconfigure(1,weight=1)
0,1分别表示第一行和第二列。weight=1表示随窗口缩放的比例为1
示例:
from tkinter import * win = Tk() win.rowconfigure(0,weight=1) win.columnconfigure(1,weight=1) Label(win,width=15,height=2,relief="groove",bg="pink").grid(row=0,column=0,sticky=N+W) #第一行第一列 Label(win,width=15,height=2,relief="groove",bg="gray").grid(row=0,column=1,sticky=N+E) #第一行第二列 Label(win,width=15,height=2,relief="groove",bg="yellow").grid(row=1,column=0,sticky=N+S+W) #第二行第一列 Label(win,width=15,height=2,relief="groove",bg="blue").grid(row=1,column=1,sticky=N+S+E) #第二行第二列 win.mainloop()
4、place()方法。可以设置组件的大小以及组件在容器中的精确位置。其参数及含义如下:
x:设置组件距离窗口左侧的水平距离
y:设置组件距离窗口顶部的垂直距离
width:设置组件的宽度
height:设置组件的高度
relx:设置组件距离容器左侧的相对距离,数值范围0-1
rely:设置组件距离容器顶部的相对距离,数值范围0-1
relwidth:组件相对父容器的宽度,数值范围0-1
relheight:组件相对父容器的高度,数值范围0-1
示例1:
from tkinter import * win = Tk() win.title("华容道") win.geometry("240x300") Label(win,text="赵云",bg="#93edd4",relief="groove",font=14).place(width=60,height=120,x=0,y=0) Label(win,text="曹操",bg="#a6e3a8",relief="groove",font=14).place(width=120,height=120,x=60,y=0) Label(win,text="黄忠",bg="#93edd4",relief="groove",font=14).place(width=60,height=120,x=180,y=0) Label(win,text="张飞",bg="#93edd4",relief="groove",font=14).place(width=60,height=120,x=0,y=120) Label(win,text="关羽",bg="#93edd4",relief="groove",font=14).place(width=120,height=60,x=60,y=120) Label(win,text="马超",bg="#93edd4",relief="groove",font=14).place(width=60,height=120,x=180,y=120) Label(win,text="卒",bg="#f3f5c4",relief="groove",font=14).place(width=60,height=60,x=60,y=180) Label(win,text="卒",bg="#f3f5c4",relief="groove",font=14).place(width=60,height=60,x=120,y=180) Label(win,text="卒",bg="#f3f5c4",relief="groove",font=14).place(width=60,height=60,x=0,y=240) Label(win,text="卒",bg="#f3f5c4",relief="groove",font=14).place(width=60,height=60,x=180,y=240) win.mainloop()
示例2:
from tkinter import * win = Tk() win.title("华容道") win.geometry("240x300") Label(win,text="赵云",bg="#93edd4",relief="groove",font=14).place(relwidth=0.25,relheight=0.4,relx=0,rely=0) Label(win,text="曹操",bg="#a6e3a8",relief="groove",font=14).place(relwidth=0.5,relheight=0.4,relx=0.25,rely=0) Label(win,text="黄忠",bg="#93edd4",relief="groove",font=14).place(relwidth=0.25,relheight=0.4,relx=0.75,rely=0) Label(win,text="张飞",bg="#93edd4",relief="groove",font=14).place(relwidth=0.25,relheight=0.4,relx=0,rely=0.4) Label(win,text="关羽",bg="#93edd4",relief="groove",font=14).place(relwidth=0.5,relheight=0.2,relx=0.25,rely=0.4) Label(win,text="马超",bg="#93edd4",relief="groove",font=14).place(relwidth=0.25,relheight=0.4,relx=0.75,rely=0.4) Label(win,text="卒",bg="#f3f5c4",relief="groove",font=14).place(relwidth=0.25,relheight=0.2,relx=0.25,rely=0.6) Label(win,text="卒",bg="#f3f5c4",relief="groove",font=14).place(relwidth=0.25,relheight=0.2,relx=0.5,rely=0.6) Label(win,text="卒",bg="#f3f5c4",relief="groove",font=14).place(relwidth=0.25,relheight=0.2,relx=0,rely=0.8) Label(win,text="卒",bg="#f3f5c4",relief="groove",font=14).place(relwidth=0.25,relheight=0.2,relx=0.75,rely=0.8) win.mainloop()
七、tkinter常用组件:
1、文本类组件:
1.1、Label标签
示例代码:
from tkinter import * win=Tk() #添加标题 win.title("斗兽棋游戏的食物链") #添加标题 # textd定义Label标签里的文本内容,bg表示Label的背景颜色 txt1=Label(win,text="象",bg="#FFEBCD",width=5,padx=4,pady=4,font="10") txt2=Label(win,text="狮",bg="#c1ffc1",width=5,padx=4,pady=4,font="10") txt3=Label(win,text="虎",bg="#FFEBCD",width=5,padx=4,pady=4,font="10") txt4=Label(win,text="豹",bg="#c1ffc1",width=5,padx=4,pady=4,font="10") txt5=Label(win,text="狼",bg="#FFEBCD",width=5,padx=4,pady=4,font="10") txt6=Label(win,text="狗",bg="#c1ffc1",width=5,padx=4,pady=4,font="10") txt7=Label(win,text="猫",bg="#FFEBCD",width=5,padx=4,pady=4,font="10") txt8=Label(win,text="鼠",bg="#c1ffc1",width=5,padx=4,pady=4,font="10") # foreground设置label组件的文字颜色 txtr1=Label(win,text="→",padx=2,pady=2,foreground="#B22222").grid(row=1,column=2) txtr2=Label(win,text="→",padx=2,pady=2,foreground="#B22222").grid(row=1,column=4) txtb1=Label(win,text="↓",padx=2,pady=2,foreground="#B22222").grid(row=2,column=5) txtb2=Label(win,text="↓",padx=2,pady=2,foreground="#B22222").grid(row=4,column=5) txtl1=Label(win,text="←",padx=2,pady=2,foreground="#B22222").grid(row=5,column=4) txtl2=Label(win,text="←",padx=2,pady=2,foreground="#B22222").grid(row=5,column=2) txtt1=Label(win,text="↑",padx=2,pady=2,foreground="#B22222").grid(row=4,column=1) txtt2=Label(win,text="↑",padx=2,pady=2,foreground="#B22222").grid(row=2,column=1) # 设置斗兽棋游戏的棋子的位置 txt1.grid(row=1,column=1) txt2.grid(row=1,column=3) txt3.grid(row=1,column=5) txt4.grid(row=3,column=5) txt5.grid(row=5,column=5) txt6.grid(row=5,column=3) txt7.grid(row=5,column=1) txt8.grid(row=3,column=1) win.mainloop()
示例-Label标签中添加图片:
from tkinter import * from PIL import Image,ImageTk win=Tk() image = Image.open(f'D:\\temp\\6.png') img = ImageTk.PhotoImage(image) Label(win,image=img).pack() win.mainloop()
如果Label组件中既有文字又有图片,则可以通过Label组件中的compound设置图片与文字的显示位置,具体参数如下:
top:图片位于文字上方
bottom;图片位于文字下方
left:图片位于文字左侧
right:图片位于文字右侧
center:文字位于图片上(图片与文字重叠,且文字在图片的上层)
1.2、Entry单行文本框
使用方法:Entry(win),示例1:
from tkinter import * win=Tk() Label(win,text="出发地:",font=14).grid(pady=10,row=0,column=0) Entry(win).grid(row=0,column=1) Label(win,text="目的地:",font=14).grid(pady=10,row=1,column=0) Entry(win).grid(row=1,column=1) win.mainloop()
如果是密码框,可以用以下方式:Entry(win,show="*")
示例2:
from tkinter import * win=Tk() Label(win,text="密码:",font=14).grid(pady=10,row=0,column=0) Entry(win,show="*").grid(row=0,column=1) win.mainloop()
示例3-登录窗口:
from tkinter import * win=Tk() win.configure(bg="#EFE5D2") Label(win,text="用户:",font=14).grid(pady=10,row=0,column=0) Entry(win).grid(row=0,column=1) Label(win,text="密码:",font=14).grid(pady=10,row=1,column=0) Entry(win,show="*").grid(row=1,column=1) Label(win,text="确定",relief="groove").grid(row=2,columnspan=2,pady=10) win.mainloop()
Entry提供的三个组件:
get():获取文本框的内容
insert():在文本框的指定位置添加内容,如:entry.insert(index,str)
delete():删除文本框中指定的内容,如:entry.delete(first,end)
示例4-相加计数器:
from tkinter import * win=Tk() win.configure(bg="#EFE5D2") def add(): res.delete(0,END) #清空显示结果的文本框的内容 add1 = int(op1.get()) add2 = int(op2.get()) res.insert(INSERT,add1+add2) #INSERT表示从当前光标处开始插入 op1=Entry(win,width=5,relief="groove") op1.grid(row=0,column=0) Label(win,text="+").grid(row=0,column=1) op2=Entry(win,width=5,relief="groove") op2.grid(row=0,column=2) Label(win,text="=").grid(row=0,column=3) res = Entry(win,width=5,relief="groove") res.grid(row=0,column=4) Button(win,text="计算",command=add,relief="groove").grid(row=0,column=5,ipadx=10) win.mainloop()
1.3、Text多行文本框
用法Text(win)。可以通过insert()方法添加初始文本。Text组件中添加图片需要创建PhotoImage()对象,然后通过image_create()引入图像。如:
photo = PhotoImage(file="D:\test\ico.png")
text.image_create(END,image=photo)
以上方法只能引入png格式的图片,如果要引入其它格式的请参考:示例-Label标签中添加图片。
示例-在文本框中添加图片、文字及按钮:
from tkinter import * from PIL import Image,ImageTk i = 0 def show(): global i i += 1 label.config(text="你点了我\t"+str(i)+"下") win = Tk() text = Text(win,width=45,height=10,bg="#cae1ff",relief="solid") image = Image.open(f'E:\\网页素材大全\\按钮\\0034.gif') photo = ImageTk.PhotoImage(image) text.image_create(END,image=photo) text.insert(INSERT,"在这里添加文本:\n") text.pack() bt = Button(win,text="你点我试试",command=show,padx=10) text.window_create("2.0",window=bt) #将按钮放在Text组件中的第2行第1列 label = Label(win,padx=10,text="你点了我0下") text.window_create("2.end",window=label) #将Label放在Text组件中的第2行最后一列 win.mainloop()
Text组件的索引方式有我种,以下是常见的几种:
line.column:如"2.3"表示第2行第4列
insert:在光标的位置插入,如上面的text.insert(INSERT,"在这里添加文本:\n")
end:最后一个字符的位置,如果字符串为end,表示所有文本的最后一个字符位置;如果字符串为line.end表示当前行的最后一个字符位置
+count chars:指定位置向后移动count个字符。如:"2.1+2 chars"表示第2行第4个字符的位置
-count chars:指定位置向前移动count个字符。如:"2.3-2 chars"表示第2行第2个字符的位置
注意:Text组件中获取字符串的索引位置时,第1行的索引为1,第1列的索引为0
示例:
from tkinter import * win = Tk() text = Text(win) text.insert(INSERT,"I love python") text.pack() print(text.get(1.2,1.6)) #获取Text组件的第1行第3列到第1行第7列的字符(love) win.mainloop()
Text组件提供了一些方法或以获取或编辑Text组件中的内容,常见方法如下:
delete():删除Text组件中的内容
get():获取文本内容
mark_set():添加标记
search():搜索文本
edit_undo():撤销操作
edit_separator():添加分割线。之后再进行撤销操作时不会撤销所有操作,只是撤销上一次的操作
示例-用Ctrl+z和Ctrl+y执行撤销和恢复操作:
from tkinter import * win = Tk() def undo1(event): text.edit_undo() #撤销操作 def redo1(event): #恢复操作 text.edit_redo() def callback(event): text.edit_separator() #每单击一次键盘就添加一个分割线,否则会撤销或恢复所有操作 text = Text(win,width=50,height=30,undo=True,autoseparators=False) text.pack() #添加提示性文字 text.insert(INSERT,'在下方可以添加文本,通过Ctrl+z撤销,Ctrl+y恢复:\n\n') text.bind('<Key>',callback) text.bind('<Control-Z>',undo1) text.bind('<Control-Y>',redo1) win.mainloop()
2、按钮类组件:
2.1、Button按钮
语法:Button(win,command=callback)
同样Button按钮也可以显示图片同样首先需要创建一个PhotoImage()对角,然后在Button按钮中引入该对象。如:
img = PhotoImage(file="test.png")
Button(win,image=img)
示例-单击按钮,增加图片:
from tkinter import * from PIL import Image,ImageTk def show(): Label(win,image=img).pack() win = Tk() image = Image.open(f'E:\\网页素材大全\\按钮\\0034.gif') img = ImageTk.PhotoImage(image) Button(win,text="添加图片",command=show).pack() win.mainloop()
Button组件的相关属性及其含义:
activebackground:按钮激活时的背景颜色
activeforeground:按钮激活时的前景颜色
bd:边框的宽度,默认为2像素
command:单击按钮时执行的方法
image:在按钮上添加图片
state:设置按钮的状态,可选的值有NORMAL(默认值)、ACTIVE、DISABELE
wraplength:限制按钮每行显示的字符数量
text:按钮的文本内容
underline:设置哪些文字带下划线。例如,取值为0,表示第一个字符带下划线;值为1表示第二个字符带下划线
示例-模拟密码输入器:
from tkinter import * from PIL import Image,ImageTk def num(a): val = pswshow.get() if len(val) < 11: #先清除原有内容,然后将原有内容同输入的值一起添加到单行文本框 pswshow.delete(0,END) pswshow.insert(0,val+" "+a) def back(): val = pswshow.get() if len(val) >= 1: #如果文本框的值长度大于2,删除最后一位 pswshow.delete(len(val) - 2,END) pswshow.config(text=val[0:len(val) - 2]) def enter(): val = pswshow.get() #弹出一个顶层窗口 win2 = Toplevel() if len(val) == 12: Label(win2,text="\n\n您的密码正确\n\n").pack() else: Label(win2, text="\n\n密码为6位数字\n\n").pack() win = Tk() win.title("密码输入器") #密码显示部分 pswshow = Entry(win,relief="solid",justify="center") pswshow.grid(row=1,columnspan=3) #键盘部分 but1 = Button(win,text="1",command=lambda :num("1")) but2 = Button(win,text="2",command=lambda :num("2")) but3 = Button(win,text="3",command=lambda :num("3")) but4 = Button(win,text="4",command=lambda :num("4")) but5 = Button(win,text="5",command=lambda :num("5")) but6 = Button(win,text="6",command=lambda :num("6")) but7 = Button(win,text="7",command=lambda :num("7")) but8 = Button(win,text="8",command=lambda :num("8")) but9 = Button(win,text="9",command=lambda :num("9")) but0 = Button(win,text="0",height=1,command=lambda :num("9")) but1.grid(row=5,sticky=W+E) but2.grid(row=5,column=1,sticky=W+E) but3.grid(row=5,column=2,sticky=W+E) but4.grid(row=6,sticky=W+E) but5.grid(row=6,column=1,sticky=W+E) but6.grid(row=6,column=2,sticky=W+E) but7.grid(row=7,sticky=W+E) but8.grid(row=7,column=1,sticky=W+E) but9.grid(row=7,column=2,sticky=W+E) img1 = Image.open(f'D:\\cnblogs\\python\\pic\\back.png') back1 = ImageTk.PhotoImage(img1) img2 = Image.open(f'D:\\cnblogs\\python\\pic\\enter.png') enter1 = ImageTk.PhotoImage(img2) butback = Button(win,image=back1,command=back) butok = Button(win,image=enter1,command=enter) butback.grid(ipady=3,row=8,sticky=W+E) but0.grid(row=8,column=1,sticky=W+E) butok.grid(ipady=3,row=8,column=2,sticky=W+E) win.mainloop()
2.2、Radiobutton单选按钮
多个按钮只能选择一个。示例:
from tkinter import * win = Tk() vali = IntVar() vali.set("male") radio1 = Radiobutton(win,variable=vali,value="male",text="男").pack() radio2 = Radiobutton(win,variable=vali,value="female",text="女").pack() win.mainloop()
Radiobutton组件的常用属性及含义:
image:指定Radiobutton显示的图片
text:指定Radiobutton显示的文本
compound:设置图片和文本的排版方式,具体可以参考Label组件中的compound属性
cursor:当鼠标停在单行按钮上时的样式
indicatoron:指定是否绘制单选按钮前员的小圆圈
selectcolor:选择框的颜色
selectimage:当该单选按钮被选中时显示的状态
state:指定单选按钮的状态
value:表示该按钮的值
variable:设置或获取当前选中的单选按钮
Radiobutton单选按钮也具有和Button一样的属性如:activebackground、activeforeground、bd、command、highlightcolor等
示例-脑筋急转弯:
from tkinter import * def result1(): print(v.get()) if v.get() == 1: re.config(text="答错了,答案是小狗,因为'旺旺仙贝:)'") elif v.get() == 2: re.config(text="答对了,因为'旺旺仙贝:)'") else: re.config(text="请选择一个答案") win = Tk() win.title("脑筋急转弯") win.geometry("300x150") Label(win,text="老师让小猫和小狗去背书,请问谁先背呢?",font=14).pack(anchor=W) v = IntVar() ans1 = Radiobutton(win,text="小猫",variable=v,value=1,selectcolor="#f1d4c9") ans1.pack(anchor=W) ans2 = Radiobutton(win,text="小狗",variable=v,value=2,selectcolor="#f1d4c9") ans2.pack(anchor=W) Button(win,text="提交",command=result1,font=14,bg="#f1c57e",relief="groove").pack() re = Label(win) re.pack() win.mainloop()
2.3、Checkbutton复选框
可以同时选择多个选项,示例:
from tkinter import * win = Tk() v1 = IntVar() Checkbutton(win,variable=v1,text="香蕉").pack() v2 = IntVar() Checkbutton(win,variable=v2,text="苹果").pack() win.mainloop()
如果选项比较多时,可以通过元组或列表存放选项显示的文本:示例:
from tkinter import * win = Tk() fruits = ("香蕉","苹果","橙子","百香果","牛油果") for fruit in fruits: var = IntVar() checkbox1 = Checkbutton(win,text=fruit,variable=var).pack(side=LEFT) win.mainloop()
判断复选框是否被选中,实际上是判断复选框绑定的值。如果绑定的变量类型为整型,那么复选框被选中,则变量的值为1,反之值为0;如果绑定的变量类型为布尔型,那么当复选框被选中时,变量值为True,返之为False
示例-问卷调查功能:
from tkinter import * def results(): sel = "" for i in range(len(str1)): if check[i].get() == 1: sel = sel+str1[i]+" " re.config(text=sel) win = Tk() win.title("调查问卷") str1 = ("读书","旅游","追剧","上网","看电影","锻炼","健身","跑步","户外运动","朋友聚会","打球","发呆") text = Label(win,text="适当放松有益身心健康,请在下方选出自己最喜欢的放松方式:",font=14).grid(row=0,column=0,columnspan=6) check = [] for i in range(len(str1)): v = IntVar() checkbox = Checkbutton(win,text=str1[i],variable=v,font=12,selectcolor="#00ffff",padx=5) checkbox.grid(row=1,column=i) check.append(v) button = Button(win,text="提交",command=results,font=14,bg="#EFB4DE").grid(row=3,column=0,pady=6,columnspan=12) re = Label(win,font=12,height=10,width=110,bg="#cfcfcf") re.grid(row=4,columnspan=12) win.mainloop()
3、菜单列表类组件:
3.1、Listbox列表框组件
可以包含一个或多个文本,以便进午单选或多选。语法:listbox = Listbox(win,option),如:
from tkinter import * win = Tk() listbox = Listbox(win) listbox.insert(END,"合肥") listbox.insert(END,"上海") listbox.pack() win.mainloop()
如果添加的选项较多,可以通过列表存储选项,然后通过for循环向列表框中添加选项。示例:
from tkinter import * win = Tk() cities = ["合肥","上海","北京","天津","重庆","香港","台湾"] listbox = Listbox(win,height=6,width=20,relief="solid") for city in cities: listbox.insert(END,city) listbox.pack() win.mainloop()
Listbox组件的相关属性及含义:
listvariable:指向一个StringVar变量,用于存放Listbox组件所有项目
selectbackground:某个选项被选中时的背景颜色
selectmode:选择模式,值可以是single(单选),browse(单选,可以拖动鼠标或使用方向键改变选项),multiple(多选),extended(多先,可以通过<Shift>、<Ctrl>或者拖动鼠标实现多选)
takefocus:指定列表框是否可以通过<Tab>键转移焦点
xscrollcommand:为列表框添加水平滚动条
yscrollcommand:为列表框添加垂直滚动条
示例-双击获取列表框中的选项:
from tkinter import * def show(ele): listbox.pack(fill=X) def typeIn(event): enc.delete(0,END) enc.insert(INSERT,listbox.get(listbox.curselection())) win = Tk() win.geometry("180x150") val = StringVar() val.set("合肥 上海 北京 天津 重庆 香港 台湾") listbox = Listbox(win,bg="#FFF8DC",selectbackground="#2C92DF",selectmode="single",height=6,width=25,listvariable=val) enc = Entry(win) enc.pack(fill=X) #为文本框绑定事件,当鼠标左键单击文本框时,执行show函数 enc.bind("<Button-1>",show) #为列表框绑定双击事件,当鼠标左键单击文本框时,执行typeIn函数 listbox.bind("<Double-Button-1>",typeIn) win.mainloop()
Listbox组件的相关方法及含义:
insert(index,text):向列表框中指定位置添加选项
delete(start,[end]):删除列表框中start-end区间的选项,如果省略end,则表示删除索引为start的选项
selection_set(start,[end]);选中列表框中start-end区间的选项,如果省略end,则表示选取索引为start的选项
selection_get(index):获取某项的内容
size():获取列表框组的长度
selection_includes():判断某项是否被选中
示例-快捷信号功能:
from tkinter import * def add(from1,to1): option = from1.get(from1.curselection()) to1.insert(END,option) print(from1.curselection()) from1.delete(from1.curselection()) win = Tk() win.title("添加快捷消息列表") win.geometry("250x200") Label(win,text="系统信号").grid(row=0,column=0) Label(win,text="快捷信号").grid(row=0,column=2) #列表内容 val1 = StringVar() #系统信号 val1.set("发起进攻 请求集合 小心草丛 跟着我") val2 = StringVar() #快捷信号 val2.set("开始撤退 清理兵线 回防高地 请求支援") listbox1 = Listbox(win,bg="#FFF8DC",selectbackground="#D15FEE",selectmode="single",listvariable=val1,height=8,width=10) listbox2 = Listbox(win,bg="#C1FFC1",selectbackground="#D15FEE",selectmode="single",listvariable=val2,height=8,width=10) listbox1.grid(row=1,column=0,rowspan=2) listbox2.grid(row=1,column=2,rowspan=2) btn1 = Button(win,text=">>>",command=lambda :add(listbox1,listbox2)).grid(row=1,column=1,padx=10) btn2 = Button(win,text="<<<",command=lambda :add(listbox2,listbox1)).grid(row=2,column=1,padx=10) win.mainloop()
3.2、OptionMenu下拉列表组件
可以单按钮展开下拉列表,并且选择其中的一项,示例:
from tkinter import * win = Tk() val = StringVar() optionmenu = OptionMenu(win,val,"合肥","上海","北京","天津") optionmenu.pack() win.mainloop()
下拉列表选项较多时,可以通过元组存储选项内容,如:
from tkinter import * win = Tk() val = StringVar() cities = ("合肥","上海","北京","天津","香港","台湾") optionmenu = OptionMenu(win,val,*cities) optionmenu.pack() win.mainloop()
示例-在下拉列表中显示歌曲列表:
from tkinter import * win = Tk() win.geometry("220x220") win.title("我的歌单") Label(text="我的歌单:").pack(fill="x",anchor="w") songs_lst = ( "My way", "Trouble is friend", "Let it be me", "My heart will go on an on", "The cup of life", "The color of wind", "Fly to the moon", ) val = StringVar() optionmenu = OptionMenu(win,val,*songs_lst) optionmenu.pack(fill="x") win.mainloop()
OptionMenu组件主要有两个方法:
set():设置下拉菜单默认被选中的值
get():获取下拉菜单当前被选中的值
示例-逻辑推理谁是小偷:
from tkinter import * def result(): ans = items[2] if v.get() == ans: re.config(text=f"答对了,就是{ans}") else: re.config(text=f"回答错误,小偷是{ans}") win = Tk() win.title("谁是小偷") win.configure(bg="#ffffcc") text = Text(win,width=50,height=13,bg="#ffffcc",font=14,relief="flat") question = "一位警察抓获四个盗窃嫌疑犯:张三、李四、王二、麻子,而他们的供词如下:\n\n张三说:“不是我偷的。”\n\n李四说:“是张三偷的。”\n\n王二说:“不是我。”\n\n麻子说“是李四偷的。”\n\n他们四人只有一人说了真话,你知道谁是小偷吗?\n" text.insert(END,question) text.grid(row=1,columnspan=4) text.config(state="disabled") items = ("张三","李四","王二","麻子") v = StringVar(win) v.set(items[0]) om = OptionMenu(win,v,*items) om.grid(row=2,columnspan=2) button = Button(win,text="确定",command=result).grid(row=2,column=1,columnspan=2) re = Label(win,padx=5,pady=5,width=60) re.grid(row=3,column=0,columnspan=3) win.mainloop()
3.3、Combobox组合框组件
Combobox组件是ttk模块的组件。相当于Entry和OptionMenu组件的组合,用户即可以在文本框中输入内容,也可以单击文本框右侧的按钮展开下拉菜单进行选择,语法如下:
Combobox(win,textvariable=StringVar(),values=("aa","bb","cc"))
示例-在窗口中添加一个组合框:
from tkinter import * from tkinter.ttk import * win = Tk() val = StringVar() cities = ("合肥","上海","北京","天津","香港","台湾") Combobox(win,textvariable=val,values=cities).pack(padx=10,pady=10) win.mainloop()
示例-以管理员身份查看报表:
from tkinter import * from tkinter.ttk import * win = Tk() win.title("Combobox使用") label1 = Label(win,text="选择管理员身份:").grid(row=1,column=0,columnspan=2,pady=10) items = ("蓝色妖姬","烈焰焚情","寒冰幽兰","岁岁芳华","朝暮盈霄","陌上开花") useroption = Combobox(win,width=12,values=items) useroption.grid(row=1,column=2,pady=10) useroption.current(0) #默认选择当前第一项 label2 = Label(win,text="查看类别:").grid(row=2,column=0,pady=10,columnspan=2) numberChosen = Combobox(win,width=12,values=("进销总览","销量","库存","进售价","账单")) numberChosen.grid(row=2,column=2,pady=0) numberChosen.current(0) button = Button(win,text="提交").grid(row=3,columnspan=4,pady=10) win.mainloop() Combobox组件常用的方法有三个: get():获取当前被选中的选项 set(value):设置当前选中的值为value current(index):设置默认选中索引为index的选项 示例-实现添加日程功能: from tkinter import * from tkinter.ttk import * def getMon(event): items = monOption.get() #当月份为4,6,9,11月时,日期为30天 if items == "4" or items == "6" or items == "9" or items == "11": mon = tuple(range(1,31)) elif items == "2": mon = tuple(range(1, 29)) else: mon = tuple(range(1, 32)) dateOption["values"] = mon def getDate(): info = label3.cget("text") temp = monOption.get()+"月"+dateOption.get()+"日\t"+text.get("0.0",END) label3.config(text=info+temp) text.delete("0.0",END) win = Tk() win.title("添加日程") number = StringVar() #1-12月 months = tuple(range(1,13)) monOption = Combobox(win,width=5,textvariable=number,values=months) monOption.current(0) monOption.grid(row=1,column=0,sticky="E",columnspan=2) #为Combobox绑定事件,当进行选择时触发事件 monOption.bind("<<ComboboxSelected>>",getMon) label1 = Label(win,text="月").grid(row=1,column=2,sticky="W") #默认每月的天数为31天 days = tuple(range(1,32)) dateOption = Combobox(win,width=5,values=days) dateOption.grid(row=1,column=3,pady=10,columnspan=2) dateOption.current(0) label2 = Label(win,text="日").grid(row=1,column=5,sticky="w") text = Text(win,width=40,height=10) text.grid(row=4,columnspan=8) button = Button(win,text="确定",command=getDate).grid(row=5,columnspan=8) label3 = Label(win) label3.grid(row=6,columnspan=8) win.mainloop()
4、容器类组件:
当窗口中的组件较多时,对组件进行管理就会比较困难,为解决这个问题就需要用到容器类组件。
4.1、Frame组件,语法:Frame(win),win是其父容器,可以省略。
示例-6个Frame容器组件:
from tkinter import * win = Tk() win.geometry("360x180") for i in range(6): if i % 2 == 0: Frame(win,bg="#B1FFBB",width=60,height=40,cursor="cross").grid(row=0,column=i,pady=10) else: Frame(win, bg="#FFD9C5", width=60, height=40, cursor="plus").grid(row=0, column=i, pady=10) win.mainloop()
将组件放在Frame组件中,也就是将Frame组件做为组件的父容器。示例:
from tkinter import * win = Tk() win.geometry("360x120") box = Frame(win,width=100,height=100,relief="groove",borderwidth=5) box.grid(row=0,column=0,padx=10,pady=10) txt = " 小明去钓鱼,结果6条无头,8条只有半个身子,9条无尾,请问小明一共钓了几条鱼?" Label(box,text=txt,wraplength=320,justify="left").grid(columnspan=4) select = ["0条","6条","8条","9条"] val = IntVar() for i in range(len(select)): Radiobutton(box,text=select[i],value=i,variable=val).grid(row=1,column=i) win.mainloop()
4.2、LabelFrame标签框架组件,使用该组件可以将一系列相关联的组件放置在一个容器内,默认情况下,该组件会绘制边框将子组件包围,并且为其显示一个标题:语法如下:
labelframe = LabelFrame(win,text="这是标题")
示例-将一组单选按钮放置在一个LabelFrame组件中:
from tkinter import * win = Tk() win.geometry("240x200") labelframe = LabelFrame(win,text="选择你的出战英雄:") labelframe.grid(row=0,column=1,ipadx=10,ipady=10) hero = StringVar() hero.set("吕布") Radiobutton(labelframe,variable=hero,text="吕布",value="吕布").grid(row=1,column=1) Radiobutton(labelframe,variable=hero,text="刘备",value="刘备").grid(row=2,column=1) Radiobutton(labelframe,variable=hero,text="关羽",value="关羽").grid(row=3,column=1) Radiobutton(labelframe,variable=hero,text="张飞",value="张飞").grid(row=4,column=1) win.mainloop()
4.3、Toplevel顶层窗口组件,可以新弹出一个窗口,而这个窗口显示在父窗口的上层,当父窗口被关闭时,Toplevel窗口也会被关闭,但是Toplevel窗口的关闭并不影响父窗口。语法:win2 = Toplevel()
示例-单击根窗口的按钮,弹出一个顶层窗口:
from tkinter import * def creat(): top = Toplevel() top.geometry("150x150") top.title("创建顶层窗口") top.configure(bg="#D8EBB8") Label(top,text="这是Toplevel顶层窗口").pack() win = Tk() win.geometry("200x200") win.configure(bg="#F7D7C4") Button(win,text="创建顶层窗口",command=creat).pack() win.mainloop()
示例-模拟游戏匹配房间:
from tkinter import * def begin(): win2 = Toplevel() win2.geometry("200x120") win2.configure(bg="#FFACAB") win2.title("准备游戏") Label(win2,text="玩家已就位,请准备!",font=14,bg="#FFACAB").pack(pady=50) def change(): win2 = Toplevel() win2.geometry("200x120") win2.configure(bg="#FFACAB") win2.title("2号棋牌室") Label(win2, text="进入2号棋牌室", font=14, bg="#FFACAB",width=35).pack(side="top", fill="x") Label(win2, text="玩家已就位,请准备!", font=16, bg="#FFACAB").pack(side="top", fill="x",pady=20) win = Tk() win.geometry("270x220") win.title("1号棋牌室") win.configure(bg="#FFCD63") label = Label(win,text="欢迎进入1号棋牌室",font=14, bg="#FFFBB5",width=35).grid(row=0,column=0,columnspan=5,ipady=8) btn1 = Button(win,text="开始对局",bg="#25A837",command=begin).grid(row=2,column=1,pady=10) btn2 = Button(win,text="更换房间",bg="#FF4A4F",command=change).grid(row=2,column=3,pady=10) win.mainloop()
4.4、Notebook选项卡组件,此组件是ttk模块提供的组件,可以显示多个选项,当用户单击选项时,下方的面板中就会显示对应的内容,语法如下:
note = Notebook(win)
note.add(pane,text="title")
其中,note表示选项卡组件,pane表示向选项卡中添加的子组件,text为该子组件的标题,单击选项卡标题即可显示对应组件。
示例-设置日期和时间的选项卡:
from tkinter import * from tkinter.ttk import Notebook win = Tk() win.title("日期和时间") note = Notebook(win,width=250,height=150) pane1 = Frame() Button(pane1,text="更改日期和时间").pack(pady=20) pane2 = LabelFrame() Checkbutton(pane2,text="显示此时钟",variable=StringVar()).pack(pady=20) pane3 = Frame() Button(pane3,text="更改设置").pack(pady=20) note.add(pane1,text="日期和时间") note.add(pane2,text="附加时钟") note.add(pane3,text="Internet时间") note.pack() win.mainloop()
示例-实现单击游戏名称显示游戏简介:
from tkinter import * from tkinter.ttk import Notebook win = Tk() win.title("游戏介绍") note = Notebook(win,width=300,height=200) pane1 = Frame() img1 = PhotoImage(file="D:\\cnblogs\\python\\pic\\pane1.png") Label(pane1,image=img1).pack() Label(pane1,text="脑洞不大,一问便知").pack(pady=20) Button(pane1,text="现在就玩").pack() pane2 = Frame() img2 = PhotoImage(file="D:\\cnblogs\\python\\pic\\pane2.png") Label(pane2,image=img2).pack() Label(pane2,text="你到底是哪一派,抽象派还是形象派").pack(pady=20) Button(pane2,text="现在就玩").pack() note.add(pane1,text="最强的大脑") note.add(pane2,text="山水泼墨画") note.pack() win.mainloop()
八、会话框与菜单:
1、messagebox会话框模块。它是tkinter模块中的一个模块,该模块根据会话框窗口的使用场合,提供了8种会话框,具体如下:
showinfo(title,message,option):显示消息提示
showwarning(title,message,option):显示警告消息
showerror(title,message,option):显示错误消息
askquestion(title,message,option):显示询问消息
askokcancle(title,message,option):显示“确定”或“取消”。确定返回True,取消返回False
askyesno(title,message,option):显示“是”或“否”。是返回True,否返回False
askyesnocancle(title,message,option):显示“是”,“否”和“取消”。是返回True,否返回False,取消返回None
askretrycancle(title,message,option):显示“重试”和“取消”。重试返回True,取消返回False
上述8种会话框的参数基本相同,title表示会话框的标题,message表示会话框的文字内容,option表示可选参数,主要有以下三个参数:
default:设置默认的按钮,即按下回车键时相应的按钮,默认为第一个按钮
icon:设定显示的图标,有INFO,ERROR,QUESTION,WARNING
parent:指定当会话关闭时,焦点指向的父窗口
1.1、showinfo(title,message,option)
示例:
from tkinter import * from tkinter.messagebox import showinfo def mess(): showinfo("Welcom!","好久不见,欢迎回来!") win = Tk() win.title("消息会话框") Button(win,text="进入游戏",command=mess).pack(padx=20,pady=20) win.mainloop()
1.2、showwarning(title,message,option)
示例:
from tkinter import * from tkinter.messagebox import showwarning def mess(): showwarning("警告!","您进入的网站可能有风险!") win = Tk() win.title("警告会话框") Button(win,text="进入网站",command=mess).pack(padx=20,pady=20) win.mainloop()
1.3、showerror(title,message,option)
示例:
from tkinter import * from tkinter.messagebox import showerror def mess(): showerror("错误提醒!","程序需要你提供读写权限,\n您拒绝的此项请求,程序将无法继续往下执行!") win = Tk() win.title("错误会话框") Button(win,text="执行程序",command=mess).pack(padx=20,pady=20) win.mainloop()
1.4、askquestion(title,message,option)
示例:
from tkinter import * from tkinter.messagebox import askquestion def mess(): boo = askquestion("是否确认!","请确认是否要执行以下操作!") if boo == "yes": win2 = Toplevel() Label(win2,text="您已确认,程序已执行!").pack() else: win2 = Toplevel() Label(win2, text="您已取消了程序执行!").pack() win = Tk() win.title("询问会话框") Button(win,text="执行程序",command=mess).pack(padx=20,pady=20) win.mainloop()
1.5、askokcancle(title,message,option)
示例:
from tkinter import * from tkinter.messagebox import askokcancel def mess(): boo = askokcancel("是否确认!","请确认是否要执行以下操作!") if boo == True: win2 = Toplevel() Label(win2,text="您已确认,程序已执行!").pack() else: win2 = Toplevel() Label(win2, text="您已取消了程序执行!").pack() win = Tk() win.title("询问会话框") Button(win,text="执行程序",command=mess).pack(padx=20,pady=20) win.mainloop()
1.6、askyesno(title,message,option)
示例:
from tkinter import * from tkinter.messagebox import askyesno def mess(): boo = askyesno("是否确认!","请确认是否要执行以下操作!") if boo == True: win2 = Toplevel() Label(win2,text="您已确认,程序已执行!").pack() else: win2 = Toplevel() Label(win2, text="您已取消了程序执行!").pack() win = Tk() win.title("询问会话框") Button(win,text="执行程序",command=mess).pack(padx=20,pady=20) win.mainloop()
1.7、askyesnocancle(title,message,option)
示例:
from tkinter import * from tkinter.messagebox import askyesnocancel def mess(): boo = askyesnocancel("是否确认!","请确认是否要执行以下操作!") if boo == True: win2 = Toplevel() Label(win2,text="您已确认,程序已执行!").pack() elif boo == False: win2 = Toplevel() Label(win2, text="您已取消了程序执行!").pack() win = Tk() win.title("询问会话框") Button(win,text="执行程序",command=mess).pack(padx=20,pady=20) win.mainloop()
1.8、askretrycancle(title,message,option)
示例:
from tkinter import * from tkinter.messagebox import askretrycancel def mess(): boo = askretrycancel("重试提醒!","打开程序出现错误,请选择重试或取消!") if boo == True: mess() else: win.quit() win = Tk() win.title("重试会话框") Button(win,text="执行程序",command=mess).pack(padx=20,pady=20) win.mainloop()
2、菜单组件:
2.1、Menu组件,tkinter中创建菜单是通过Menu组件来实现的,语法:menu1 = Menu(win,option)
要在窗口中添加菜单,仅添加菜单组件是不够的,还需要添加菜单项,并且为窗口配置菜单,添加菜单项可以通过add_command()方法实现,如:
menu1.add_command(label="开始",command=callback)
示例:
from tkinter import * def callback(): pass win = Tk() win.title("菜单") win.geometry("300x300") menu1 = Menu(win,cursor="hand2") menu1.add_command(label="开始",command=callback) menu1.add_command(label="说明",command=callback) menu1.add_command(label="退出",command=callback) win.config(menu=menu1) win.mainloop()
2.2、制作二级下拉菜单:
Menu组件的常用方法及含义:
add_comand(option):添加一个命令菜单项
add_cascade(option):添加一个父菜单
add_checkbutton(option):添加一个菜单项,该菜单项为多选按钮
add_radiobutton(option):添加一个菜单项,该菜单项为单选按钮
add_separator(option):添加一条分隔线
delete(index1,index2):删除index1-index2(含)的所有菜单项
entrycget(index,option):获得指定菜单项的某选项的值,index指定菜单项的索引值
entryconfig(index,option):设置指定菜单项的某选项的值,index指定菜单项的索引值
index(index):返回index参数相对应的选项的序号
insert(index,itemType,option):插入指定类型的菜单项到index参数指定的位置
insert_cascade(index,option):在index参数指定的位置添加一个父菜单
insert_checkbutton(index,option):在index参数指定的位置添加一个复选框
insert_radiobutton(index,option):在index参数指定的位置添加一个单选按钮
insert_command(index,option):在index参数指定的位置添加一个子菜单
insert_separator(index,option):在index参数指定的位置添加一个分割线
invoke(index):调用index参数指定的菜单选项相关系的方法
post(x,y):在指定位置显示弹出菜单
type(index):获得index参数指定菜单项的类型,返回值为:command,cascade,checkbutton,radiobutton,separator
unpost():移除弹出菜单
yposition(index):返回index参数指定的菜单项的垂直偏移位
option参数的值及含义:
postcommand:其属性值为一个方法,表示当菜单被打开时调用该函数
tearoff:设置菜单能否从窗口中分离(默认True)
cursor:鼠标悬停Menu组件上时,鼠标的样式
tearoffcommand:当菜单被分离时执行的方法
background(bg):设置背景颜色
selectcolor:当菜单项被选中为单选按钮或多选按钮时,选中标志的颜色
activebackground:当Menu组件处理active状态(通过state设置)的背景颜色
activeborderwidth:当Menu组件处理active状态(通过state设置)的边框宽度
activeforeground:当Menu组件处理active状态(通过state设置)的前景颜色
borderwidth(bd):指定边框宽度
disabledforeground:当Menu组件处理disabled状态(通过state设置)的前景颜色
font:指定Menue组件中的文字样式
foreground(fg):指定Menu组件的前景颜色
relief:指定边框样式
title:被分离的菜单的标题,默认标题为父菜单的名字
示例-为城市列表添加弹出式菜单:
from tkinter import * def pop1(): menu2_2.post(win.winfo_x()+60,win.winfo_y()+120) win = Tk() menu1 = Menu(win) menu2_1 = Menu(menu1,tearoff=False) menu1.add_cascade(label="城市",menu=menu2_1) menu2_1.add_command(label="合肥") menu2_1.add_command(label="上海") menu2_1.add_command(label="北京") menu2_1.add_command(label="天津") menu2_1.add_command(label="重庆") menu1.add_command(label="修改",command=pop1) menu2_2 = Menu(menu1,tearoff=False) menu2_2.add_command(label="添加城市") menu2_2.add_command(label="修改城市") menu1.add_command(label="退出",command=win.quit) win.config(menu=menu1) win.mainloop()
示例-设置窗口的文字样式及窗口大小:
from tkinter import * from tkinter.ttk import * def max_win(event): win.geometry("600x400") def normal_win(event): win.geometry("300x200") def txt(): global val global font_size global top top = Toplevel(win) val = StringVar() val.set("宋体") font_family = ("宋体","黑体","方正舒体","楷体","隶书","方正姚体") family = Combobox(top,textvariable=val,values=font_family) family.grid(row=0,column=0) font_size = Spinbox(top,from_=12,to=30,increment=2,width=10) font_size.grid(row=0,column=1) btn1 = Button(top,text="确定",command=font_set) btn1.grid(row=1,column=1) def font_set(): font1 = (val.get(),font_size.get()) label.config(font=font1) win = Tk() win.geometry("300x200") menu1 = Menu(win) menu2_1 = Menu(menu1) menu1.add_cascade(label="窗体",menu=menu2_1) menu2_1.add_command(label="最大化",accelerator="Ctrl+Up",command=lambda :max_win("")) menu2_1.add_command(label="恢复窗口",accelerator="Ctrl+Down",command=lambda :normal_win("")) menu2_1.add_command(label="最小化",command=win.iconify) menu2_1.add_separator() menu2_1.add_command(label="关闭",command=win.quit) menu2_2 = Menu(menu1,tearoff=0) menu1.add_cascade(label="自定义",menu=menu2_2) menu2_2.add_command(label="文字设置",command=txt) win.config(menu=menu1) label = Label(win,text="这是一个窗口") label.grid(row=0,column=0) win.bind_all("<Control-Up>",max_win) win.bind_all("<Control-Down>",normal_win) win.mainloop()
2.3、制作工具栏:
示例-实现猜成语游戏: num = 0 # 当前游戏多少关 # 通过数组存储成语和成语的含义 idiom = ["别出心裁", "白云苍狗", "暴虎冯河", "鞭长莫及", "并行不悖", "安土重迁", "不耻下问", "不胫而走", "安步当车", "爱莫能助", "白驹过隙"] idiom_means = ["独出巧思,不同流俗", "比喻世事变幻无常", "比喻有勇无谋,鲁莽冒险", "本意为马鞭虽长,但打不到马肚子上,,比喻虽有力,力量也打不到", "彼此同时进行,不相妨碍", "留恋故土,不肯轻易迁移", "比喻谦虚好学,不介意向学识或地位不及自己的人请教", "消息传的很快", "从容的步行,就当乘车一般", "心里愿意帮助,但是力量做不到", "形容时间过得很快,像白马在细小的缝隙前一闪而过", ] # 判断输入成语是否正确 def panduan(): global num a = entry.get() if a == idiom[num]: num += 1 if (num >= len(idiom)): boo = askyesno("成功过关", "恭喜!已过完所有关卡,是否重新过关?") if boo == True: num = 0 panduan() else: win.quit() entry.delete(0, END) means.config(text=idiom_means[num]) level.config(text="第 " + str(num + 1) + " 关") #手动切换至下一关 def next1(event): global num num += 1 panduan() # 重新开始,关卡重置为0 def restart(event): global num num = 0 panduan() # 显示游戏规则 def show1(): showinfo("游戏规则","根据成语的含义猜成语,正确则自动跳转至下一关") # 提示当前成语的第一个字 def tip(): str=idiom[num][0] entry.delete(0,END) entry.insert(0,str) from tkinter import * from tkinter.messagebox import * win = Tk() win.geometry("250x200") win.title("成语猜猜猜") # 工具栏部分 menu1 = Menu(win) # 创建顶级菜单 menu2_1 = Menu(menu1) # 创建第二级菜单 menu1.add_cascade(label="游戏", menu=menu2_1) # 将第二级菜单添加到顶级菜单并设置显示的内容 menu2_1.add_command(label="下一关", command=lambda:next1(""), accelerator="Ctrl+N") menu2_1.add_command(label="重新开始", command=lambda :restart(""), accelerator="Ctrl+R") menu2_1.add_separator() # 添加分割线 menu2_1.add_command(label="退出", command=win.quit) # 退出游戏,关闭窗口 menu2_2 = Menu(menu1) # 创建第二个二级菜单 menu1.add_cascade(label="帮助", menu=menu2_2) # 将第二个二级级菜单添加到顶级菜单并设置显示的内容 menu2_2.add_command(label="游戏规则",command=show1) # 添加二级菜单的子菜单 menu2_2.add_command(label="提示",command=tip) # 添加二级菜单的子菜单 win.config(menu=menu1) # 窗口内容 level = Label(win, font=14, text="第 1 关") # 当前第几关 level.grid(row=0, column=0, columnspan=4, sticky=E) # 显示成语的含义 means = Label(win, text=idiom_means[0], font=14, width=30, bg="#D8F3F0", height=3, wraplength="200") means.grid(row=1, column=0, pady=10, columnspan=4) entry = Entry(win, font=14) # 输入成语 entry.grid(row=2, column=1, sticky=E) btn = Button(win, text="确定", command=panduan).grid(row=2, column=2) win.bind_all("<Control-n>", next1) # 绑定键盘事件 win.bind_all("<Control-r>", restart) # 绑定键盘事件 win.mainloop()
2.4、树形菜单,Treeview组件是ttk模块的组件,可以在窗口中添加树形菜单或表格,并且可以对表格和或菜单中的内容进行增删改查。
Treeview组件树状结构和表格与一体,用户可以使用该组件设计表格或树形菜单,并且设置树形菜单时,可以折叠或展开子菜单,语法如下:
tree = Treeview(win,option)
Treeview组件的参数及含义:
columns:其值为列表,列表的每一个元素代表一个列表标识符的名称,列表的长度为列的长度
displaycolumns:设置列表是否显示以衣显示顺序,也可以使用"#all"表示全部显示
height:表格的高度(表格中可以显示几行数据)
padding:标题栏内容距离组件边缘的间距
selectmode:字义选择行的方式,extended可以通过Ctrl+鼠标选择多行(默认值);browse只能选择一行;none表示不能改变选择
show:表示选择哪些列,其值有:tree headings(显示所有列),tree(显示第一列(图标栏));headings(显示除第一列以外的其它列)
示例-在表格中统计游戏中各角色的类型以及操作难易度:
from tkinter import * from tkinter.ttk import * win = Tk() tree = Treeview(win,columns=("hero","type","operate"),show="headings",displaycolumns=(0,1,2)) tree.heading("hero",text="英雄",anchor="center") tree.heading("type",text="类型",anchor="center") tree.heading("operate",text="操作难易程度",anchor="center") tree.insert("",END,values=("孙尚香","射手","5")) tree.insert("",END,values=("孙策","战士","3")) tree.insert("",END,values=("小乔","辅助","3")) tree.insert("",END,values=("大乔","法师","4")) tree.pack() win.mainloop()
添加树形菜单后,需要通过insert()方法添加菜单的子项目item。语法如下:
tree.insert(父对象,插入位置,ID,option)
分别是:
父菜单的ID;插入位置,程序员为菜单设置的ID,若省略,则由Treeview自动分配;option是可选参数,其参数及含义如下:
text:属性菜单中子项目显示的名称
image:子项目前面的图标
values:子项目一行的值,未赋值的列是空列,超过列的长度会被截断
open:子菜单展开或关闭
tags:与item关联的标记
示例-树形显示近一周的天气状况:
from tkinter import * from tkinter.ttk import * win = Tk() tree = Treeview(win, columns=("date", "temperature")) tree.heading("#0", text="天气") # 设置图标栏的标题 tree.heading("date", text="日期") tree.heading("temperature", text="气温") rain = PhotoImage(file="D:\\cnblogs\\python\\pic\\rainheardly.png") # 定义图标 storm = PhotoImage(file="D:\\cnblogs\\python\\pic\\storm.png") sunny = PhotoImage(file="D:\\cnblogs\\python\\pic\\sunny.png") tree.insert("", END, values=("4月1日", "-3~5"), image=rain, text=" 中到暴雨") # 添加子项目 tree.insert("", END, values=("4月2日", "-3~7"), image=sunny, text=" 晴") tree.insert("", END, values=("4月3日", "0~8"), image=storm, text=" 雷阵雨") tree.insert("", END, values=("4月4日", "1~04"), image=sunny, text=" 晴") tree.insert("", END, values=("4月5日", "2~04"), image=sunny, text=" 晴") tree.insert("", END, values=("4月6日", "2~05"), image=sunny, text=" 晴") tree.insert("", END, values=("4月7日", "2~04"), image=rain, text=" 晴") tree.pack() win.mainloop()
为树形菜单添加子菜单。
使用Treeview组件添加子菜单时,需要通过ID绑定父元素,这个ID可以通过程序员手动分配,如果程序员忽略了ID,则由Treeview组件自动分配,如下:
tree.insert("",0,"wei",text="魏")
shu = tree.insert("",1,text="蜀")
wu = tree.insert("",2,text="吴")
三行的ID分别为:wei,shu,wu
示例-在树形菜单中显示三国的开国皇帝:
from tkinter import * from tkinter.ttk import * win = Tk() tree = Treeview(win) tree.heading("#0",text="开国皇帝") tree.insert("",0,"wei",text="魏") shu = tree.insert("",1,text="蜀") wu = tree.insert("",2,text="吴") tree.insert("wei",0,text="曹丕") tree.insert(shu,0,text="刘备") tree.insert(wu,0,text="孙权") tree.pack() win.mainloop()
菜单项的获取与编辑。Treeview组件提供了一些虚拟事件和方法,主要如下:
Treeview组件虚拟事件及含义:
TreeviewSelect:当选项发生变化时,触发某事件
TreeviewOpen:当菜单项items的open=True时,触发某事件
TreeviewClose:当菜单项items的open=False时,触发某事件
Treeview组件常用方法及含义:
bbox(item,column=None):返回一个item的范围,如果column指定了列,则返回元素的范围,如果item不可使,则返回空值
get_children(item=None):返回item所有items列表,如果item没有指定,则返回根目录的item
set_children(item,*newchildren):设置item的新的子itemss,这里的设置指的是全部替换
column(column,option=None,**kw):设置或返回各列的属性。column是标识符,option若不设置,则返回所有属性的字典
delete(*item):删除item及子item
detach(*item):取消item和子item的链接,可以在另一个点重新输入,但不会显示。根item的链接无法取消
exists(item):判断item是否在Treeview组件中,若在则返回True
focus(item=None):设置或返回获得焦点的item,若不指定item或无item获得焦点,则返回空值
heading(column,option=None,**kw):查询或修改指定的标题选项,column列为标识符,option若不设置,则返回所有属性的字典,若设置,则返回该属性的属性值
insert(parent,index,iid=none,**kw):创建新的item并返回新建item的标识符
item(item,option=None,**kw):查询或修改指定item的选项
selection():返回所有选中的items列表
selection_set(*item):设置项目为新的选择
selection_add(*item):从选择项中添加项
selection_remove(*item):从选择项中删除项
selection_toggle(*item):切换项目中每个项目的选择状态
set(item,column=None,value=None):指定item,如果不设定column和value,则返回它们的字典;若设置了column,则返对应的value,若value也设定了,则做相应的修改
示例-统计个个出行记录:
from tkinter import * from tkinter.ttk import * def setdat(event): temp = monsel.get() if temp == 2: dat["value"] = tuple(range(1,29)) elif temp == 4 or temp == 6 or temp == 9 or temp == 11: dat["value"] = tuple(range(1, 31)) else: dat["value"] = tuple(range(1, 32)) def get1(): if len(entry.get()) == 0: return False else: h = str(horsel.get()) if horsel.get()>=10 else "0"+str(horsel.get()) m = str(minsel.get()) if minsel.get()>=10 else "0"+str(minsel.get()) item1 = (str(mon.get())+" 月 "+str(dat.get())+" 日 ",h+":"+m,entry.get()) if not tree.focus() == "": tree.insert("",tree.index(tree.focus()),values=item1) del1() else: tree.insert("",END,values=item1) reset1() def del1(): if tree.focus() == "": return False tree.delete(tree.focus()) def edt(event): temp = tree.set(tree.focus()) d = temp["date"].split("月") t = temp["time"].split(":") monsel.set(d[0]) datsel.set(int(d[1].split("日")[0])) horsel.set(t[0]) minsel.set(t[1]) entry.delete(0,END) entry.insert(INSERT,temp["depart"]) def reset1(): monsel.set(1) datsel.set(1) horsel.set(0) minsel.set(0) entry.delete(0,END) win = Tk() frame = Frame() frame.grid() Label(frame,text="日期:").grid(row=0,column=0) monsel = IntVar() #绑定月份选项 monsel.set(1) mon = Combobox(frame,values=tuple(range(1,13)),textvariable=monsel,width=5) mon.grid(row=0,column=1) mon.bind("<<ComboboxSelected>>",setdat) #当月份发生变化时对应日期也变化 Label(frame,text="_").grid(row=0,column=2) datsel = IntVar() datsel.set(1) dat = Combobox(frame,values=tuple(range(1,32)),textvariable=datsel,width=5) dat.grid(row=0,column=3) Label(frame,text="时间:").grid(row=0,column=4,columnspan=2,sticky=S+E) horsel = IntVar() horsel.set(0) hor = Spinbox(frame,from_=0,to=24,textvariable=horsel,width=5) hor.grid(row=0,column=6) Label(frame,text=":").grid(row=0,column=7) minsel = IntVar() minsel.set(0) min = Spinbox(frame,from_=0,to=59,textvariable=minsel,width=5) min.grid(row=0,column=8) Label(frame,text="出发地:").grid(row=0,column=9) entry = Entry(frame) entry.grid(row=0,column=10) Button(frame,text="确定",command=get1).grid(row=0,column=11) Button(frame,text="删除",command=del1).grid(row=0,column=12) tree = Treeview(win,columns=("date","time","depart"),show="headings") tree.heading("date",text="日期") tree.heading("time",text="时间") tree.heading("depart",text="出发地") tree.grid(row=1,column=0) tree.bind("<<TreeviewSelect>>",edt) win.mainloop()
2.5、综合案例-眼力测试小游戏:
i = 84 # 提示 def help(): showwarning("提醒", "第4行") # 暂停与重新开始游戏 def game(): boo = askyesnocancel("暂停", "是否停止本游戏,点击是,重新开始游戏,点击否暂停游戏") if boo == True: i = 0 label.config(text=i) elif boo==False: i=84 label.config(text=i) #每点击错误一次,得分就减1 def wrong(): global i i -= 1 label.config(text=i) # 找到与众不同的汉字 def suc(): top = Toplevel(win) Label(top, text="恭喜,找到了\n,得分为"+str(i), fg="red").grid(row=0, column=0, padx=10, pady=10) from tkinter import * from tkinter.messagebox import * win = Tk() win.title("为游戏窗口添加菜单") menu1 = Menu(win) # 创建顶级菜单 # 添加工具栏 menu1.add_command(label="游戏", command=game) menu1.add_command(label="帮助", command=help) menu1.add_command(label="退出", command=win.quit) win.config(menu=menu1) # 显示菜单 for c in range(6): for j in range(14): Button(win, text="大", width=1,command=wrong).grid(row=c, column=j) Button(win, text="女", width=1, command=suc).grid(row=3, column=3) label = Label(win, font=14, fg="red", text=84) label.grid(row=8, column=0, columnspan=14) win.mainloop()
九、canvas绘图
canvas组件也是tkinter模块中的组件,主要用途就是绘制图形、文字、设计动画,甚至可以将其它的小部件放置在画布上。但在使用canvas组件之前,需要先定义canvas画布。定义canvas画布的语法如下:
canvas = Canvas(win,option)
其中win为canvas组件的父容器,option为canvas组件的相关参数。具体参数如下:
bd:设置边框宽度,默认为2像素
bg:设置背景颜色
confine:如果为true(默认值),则画布不能滚动到可滑动区域外
cursor:设置鼠标悬停canvas组件上时的形状
height:设置画布的高度
width:设置画布的宽度
relief:设置边框的样式
scrollregion:其值为元素tuple(w.n.e.s),分别定义左、上、右、下四个方向可滚动的最大区域
xscrollincrement:水平方向滚动时,请求滚动的数量值
yscrollincrement:垂直方向滚动时,请求滚动的数量值
xscrollcommand:绑定水平滚动条
yscrollcommand:绑定垂直滚动条
示例-在窗口中创建画布:
from tkinter import * win = Tk() win.title("创建canvas画布") win.geometry("300x200") canvas = Canvas(win,width=200,height=200,bg="#EFEFA3").pack() win.mainloop()
2、绘制基本图形:
2.1、绘制线条:线条是canvas组件中比较常见的元素之一,canvas组件中的线条可以有多个顶点,在绘制线条时需要按顺序绘制各个顶点。canvas组件中绘制线条是通过create_line()方法实现的。其语法如下:
canvas.create_line(x1,y1,x2,y2...xn,yn,option)
其中x1,y1是线段的起点坐标,x2,y2是第二个顶点坐标……直线的终点。option为线条的可选参数,具体参数及含义如下:
arrow:是否添加箭头,默认为无箭头,另外还可以设置其值为FIRST(起始端右箭头)、LAST(末端右箭头)、BOTH(两端都有箭头)
arrowshap:设置箭头的形状,其值为元素d1、d2、d3,分别表示三角形箭头的底、斜边和高的距离
capstyle:线条终点的样式,其属性值有butt(默认值)、projecting和round
dash:设置线条为虚线,以及虚线的形状,其值为元组x1、x2,表示x1像素的实绩和x2像素的空白交替出现
dashoffset:与dash相近,不过含义为x1像素的空白和x2像素的实绩交替显示
fill:设置线条颜色
joinstyle:设置线条焦点的颜色,其值有round(默认值)、bevel和miter
stipple:绘制位图线条
width:设置线条宽度
示例-使用线条绘制五角星:
from tkinter import * win = Tk() win.title("绘制五角星") win.geometry("300x200") canvas = Canvas(win,width=200,height=200) canvas.create_line((14,65,66,65,83,19,99,64,148,64,111,96,126,143,83,113,44,142,58,97,14,65),fill="red") canvas.pack() win.mainloop()
2.2、绘制矩形:绘制矩形可以使用create_rectangle()方法,其语法如下:
create_rectangle(x1,y1,x2,y2,option)
其中x1,y1为矩形的左上角坐标;x2,y2为矩形的右下角坐标,当x2-x1=y2-x1时,所绘制的图形为正方形;而option为矩形的可选参数,其中dash,dashoffset,stipple,width等参数的含义和线条的基本类似,另外可以通过outline属性设置矩形的轮廓颜色。
示例-在画布中绘制一个正文形并通过方向键移动:
def up1(event): #move()方法实现rect向上移动2个单位 canvas.move(rect, 0, -2) def down1(event): # move()方法实现rect向下移动2个单位 canvas.move(rect, 0, 2) def left1(event): # move()方法实现rect向左移动2个单位 canvas.move(rect, -2, 0) def right1(event): # move()方法实现rect向右移动2个单位 canvas.move(rect, 2, 0) from tkinter import * win = Tk() win.title("键盘控制矩形移动") win.geometry("300x200") canvas = Canvas(win,width=200,height=200,relief="solid") rect = canvas.create_rectangle(10,10,50,50,fill="#C8F7F2") canvas.pack() win.bind("<Up>",up1) win.bind("<Down>",down1) win.bind("<Left>",left1) win.bind("<Right>",right1) win.mainloop()
move()方法中三个参数的含义依次为:平移的对象、水平移动距离、垂直移动距离
2.3、绘制椭圆:绘制椭圆和圆形使用的方法相同,用create_oval()方法,其语法如下:
create_oval(x1,y1,x2,y2,option)
其中x1,y1为椭圆的左上角坐标;x2,y2为椭圆的右下角坐标。option参数及其含义可以参考线段的。
示例-绘制人脸简笔画:
from tkinter import * win = Tk() win.title("绘制人脸") win.geometry("300x200") canvas = Canvas(win,width=200,height=200,relief="solid") cir1 = canvas.create_oval(34,68,143,127,fill="#C8F7F2") cir2 = canvas.create_oval(59,83,71,99,fil="#E6F1B7") cir2_1 = canvas.create_oval(61,86,71,94,fill="#000000") cir3 = canvas.create_oval(101,83,113,99,fil="#E6F1B7") cir3_1 = canvas.create_oval(100,86,109,94,fill="#000000") mouth = canvas.create_oval(78,110,92,120,fill="red") canvas.pack() win.mainloop()
2.4、绘制圆弧与扇形:
绘制圆弧与扇形都使用create_arc()方法,只是使用的参数不同:
2.4.1、绘制圆弧:绘制圆弧除了需要指定圆弧的起始坐标与终点坐标,还需要指定圆弧的角度,其语法如下:
canvas.create_arc(x1,y1,x2,y2,extent=-180,start=30,style=ARC,option)
其中x1,y1为圆弧的起点坐标;x2,y2为圆弧的终点坐标;extent表示圆弧的角度,默认为90度;start为弧形的起始弧度,默认值为0;style表示绘制的类型,其属性值有3个,分别是ARC、CHORD、PIESLICE;option可以参考线段的。
示例-style属性值的演示:
from tkinter import * win = Tk() win.title("绘制圆弧") win.geometry("460x200") canvas = Canvas(win,width=500,height=400,relief="solid") canvas.create_arc(20,40,150,150,extent=120,outline="red",start=30,width=2,style=ARC) canvas.create_arc(170,40,300,150,extent=120,outline="red",start=30,width=2,style=CHORD) canvas.create_arc(320,40,450,150,extent=120,outline="red",start=30,width=2,style=PIESLICE) canvas.pack() win.mainloop()
2.4.2、绘制扇形:绘制扇形同样使用create_arc()方法,该方法中不仅需要指定扇形的起始坐标和终点坐标,还需要指定style=PIESLICE,以及设定扇形的角度和超始角度,其语法如下:
canvas.create_arc(x1,y1,x2,y2,extent=-180,start=30,style=ARC,style=PIESLICE)
示例-综合使用canvas组件中的方法:
from tkinter import * win = Tk() win.title("绘制西瓜状雪糕") win.geometry("300x200") canvas = Canvas(win,width=400,height=300,relief="solid") canvas.create_line(95,124,95,194,fill="#E9D39D",width=12,capstyle=ROUND) #雪糕把手 canvas.create_arc(5,-70,185,162,extent=-40,outline="#32e143",fill="#32E143",start=-70,width=2,style=PIESLICE) #西瓜的皮 canvas.create_arc(8,-67,181,155,extent=-40,outline="#E92742",fill="#E92742",start=-70,width=2,style=PIESLICE) #西瓜的瓤 #西瓜的籽: canvas.create_arc(92,74,97,79,extent=159,fill="#000",width=2,style=ARC) canvas.create_arc(97,94,102,99,extent=180,start=90,fill="#000",width=2,style=ARC) canvas.create_arc(110,124,113,127,extent=359,fill="#000",width=2,style=ARC) canvas.create_arc(90,134,93,137,extent=359,fill="#000",width=2,style=ARC) canvas.pack() win.mainloop()
2.5、绘制多边形:绘制多边形同绘制线条一样,需要按顺序(顺时针或逆时针方向都可以)依次描绘多边形的各个顶点,而绘制多边形需要使用create_polygon()方法,其语法如下:
canvas.create_polygon(x1,y1,x2,y2,xn,yn,option)
其中(x1,y1),(x2,y2)以及xn,yn为顺时针方向或逆时针方向依次描绘的多边形的顶点;option可以参考线条的。
示例-七巧板拼成的松鼠:
from tkinter import * win = Tk() win.title("绘制松鼠") win.geometry("240x260") canvas = Canvas(win,width=250,height=250,relief="solid") canvas.create_polygon(27,8,27,62,54,34,fill="#fbfe0d") #左耳 canvas.create_polygon(54,34,81,8,81,63,fill="red") #右耳 canvas.create_polygon(81,63,54,35,25,61,53,90,fill="#0001fc") #脸 canvas.create_polygon(81,63,81,176,138,121,fill="#32ccfe") #身体 canvas.create_polygon(81,97,43,135,81,174,fill="#fdcbfe") #上半身 canvas.create_polygon(139,119,60,198,140,198,fill="#02cd02") #下半身 canvas.create_polygon(140,198,167,170,223,170,196,198,fill="#9b01ff") #尾巴 canvas.pack() win.mainloop()
2.6、绘制文字:绘制文字需要使用create_text()方法,其语法如下:
create_text(x,y,text=str,option)
其中x,y为字符串的中心位置;text为输出的字符串;option为文字的相关属性。如font、fill以及justify
示例-绘制随机颜色的文字:
from tkinter import * import random fill_color = ["#B0E3DD","#E19644","#6689E1","#E16678","#66E1CA"] font_family = ["方正舒体","方正姚体","华文琥珀","宋体","华文行楷","楷体","华文新魏","隶书"] def draw(): canvas.delete("all") #清空画布 color = fill_color[random.randint(0,4)] family = font_family[random.randint(0,7)] canvas.create_text(160,60,text=str,font=(family,20),fill=color) win = Tk() win.title("绘制文字") win.geometry("330x200") canvas = Canvas(win,width=300,height=160,relief="solid") str = "人因梦想而伟大" canvas.pack() Button(win,text="绘制",command=draw).pack() win.mainloop()
2.7、绘制图像:绘制图像使用的方法是create_image(),具体语法如下:
canvas.create_image(x,y,image=house1,option)
其中x,y中为图像左上角顶点坐标;image为添加的图像;option参数有anchor
示例-用鼠标手动小鸟帮其回家:
from tkinter import * from tkinter.messagebox import * #拖动鼠标,移动小鸟 def draw(event): canvas.coords(bird,event.x,event.y) #判断小鸟是否回家 def panduan(event): canvas.coords(bird,event.x,event.y) x1 = abs(event.x-340) y1 = abs(event.y-70) if x1<70 and y1<75: showinfo("小鸟回家","谢谢你成功帮小鸟回家") win = Tk() win.title("帮小鸟回家") win.geometry("400x320") canvas = Canvas(win,width=400,height=320,relief="solid",bg="#E7D2BB") bird1 = PhotoImage(file="bird.png") house1 = PhotoImage(file="house.png") house = canvas.create_image(340,70,image=house1) bird = canvas.create_image(150,250,image=bird1) canvas.grid(row=0,column=0,columnspan=2) canvas.bind("<B1-Motion>",draw) canvas.bind("<ButtonRelease-1>",panduan) win.mainloop()
2.8、拖动鼠标绘制图形:
canvas组件中并不能直接通过鼠标绘制线条,但是可以通过为canvas组件绑定鼠标事件。移动鼠标时,在鼠标的坐标位置绘制圆形,然后将一系列圆形连在一起形成线条。
示例-用鼠标写字:
from tkinter import * def draw(event): global text1 text1 = canvas.create_oval(event.x,event.y,event.x+10,event.y+10,fill="green",outline="") def delete1(): canvas.delete("all") can() win = Tk() win.title("书法秀") win.geometry("420x420") canvas = Canvas(win,width=400,height=400,relief="solid",bg="#F1E9D0") def can(): rect = canvas.create_rectangle(4,4,400,385,outline="red",width=2) line1 = canvas.create_line(2,198,400,198,dash=(2,2),fill="red") line2 = canvas.create_line(198,2,198,400,dash=(2,2),fill="red") line3 = canvas.create_line(0,0,400,400,dash=(2,2),fill="red") line4 = canvas.create_line(0,400,400,0,dash=(2,2),fill="red") canvas.pack() canvas.bind("<B1-Motion>",draw) Button(win,text="清屏",command=delete1).pack(side="bottom") can() win.mainloop()
2.9、canvas组件设计动画:
canvas组件不仅可以绘制基本图形和图像,还可以设计动画,而设计动画主要通过移动或改变canvas画布组件中元素坐标来实现。移动和改变坐标主要通过两个方法,分别是move()和coords(),具体方法如下:
move(ID,x,y):表示ID(canvas中需要移动的形状的编号)水平方向向右移动x单位长度,垂直向下移动y单位长度。
coords(shape,x1,y1,x2,y2):相当于重新设置所绘制图形的坐标。shape为所修改开形状的名称。
除此之外,每当元素的位置改变,需要强制刷新窗口中的内容,强制刷新窗口的方法是update()。
示例-小猫钓鱼游戏:
from tkinter import * from tkinter.messagebox import * import time x1 = 350 #鱼的初始水平坐标 step = 2 op = 1 #控制鱼向左移动或向左移动 bar = 1 #当bar=0时鱼不再移动 def move1(): global bar,x1,fish,op bar = 1 if x1 >= 350: op = -1 canvas.delete(fish) fish = canvas.create_image(x1,50,image=fish1) if x1 <= 0: op = 1 canvas.delete(fish) fish = canvas.create_image(x1, 50, image=fish2) x1 = x1+op*step canvas.coords(fish,(x1,50)) def catch_fish(): canvas.coords(cat,(150,50)) global bar bar = 0 if abs(x1-50)<=160 and abs(x1-50)>=40: showinfo("成功提示","恭喜你,成功钓到一条鱼") else: showinfo("失败提示","遗憾哦,钓鱼失败") def move_fish(): while bar: move1() time.sleep(0.1) win.update() win = Tk() win.title("小猫钓鱼") win.geometry("400x400") canvas = Canvas(win,width=400,height=320,relief="solid",bg="#E7D2BB") cat1 = PhotoImage(file="cat.png") fish1 = PhotoImage(file="fish.png") fish2 = PhotoImage(file="fish1.png") fish = canvas.create_image(350,50,image=fish1) cat = canvas.create_image(150,250,image=cat1) canvas.grid(row=0,column=0,columnspan=2) Button(win,text="开始",command=move_fish).grid(row=1,column=0) Button(win,text="钓鱼",command=catch_fish).grid(row=1,column=1) win.mainloop()
示例-碰壁的小球:
from tkinter import * from PIL import Image,ImageTk import random,math wid = 500 hig = 340 class ball(): def __init__(self): btn.config(state="disabled") self.x1 = random.randint(50,90) self.y1 = random.randint(50,90) self.img1 = Image.open("balll1.png") self.dig = 0 self.img = ImageTk.PhotoImage(self.img1.rotate(self.dig)) self.speed_x = 5 self.speed_y = 5 self.balls = canvas.create_image(self.x1,self.y1,image=self.img) self.move() def move(self): canvas.delete(self.balls) self.img = ImageTk.PhotoImage(self.img1.rotate(self.dig)) if self.dig >= 360: self.dig = 0 if self.x1 < 60: self.speed_x = math.fabs(self.speed_x) if self.x1 + 65 > wid: self.speed_x = -self.speed_x if self.y1 < 60: self.speed_y = math.fabs(self.speed_y) if self.y1 + 65 > hig: self.speed_y = -self.speed_y self.x1 += self.speed_x self.y1 += self.speed_y self.balls = canvas.create_image(self.x1,self.y1,image=self.img) win.after(50,self.move) win = Tk() win.title("碰壁的小球") win.geometry("500x380") canvas = Canvas(win) canvas.place(x=0,y=0,width=wid,height=hig) bg = ImageTk.PhotoImage(file="bgball.png") canvas.create_image(wid,hig,image=bg,anchor="se") btn = Button(win,text="开始",command=ball) btn.place(x=200,y=hig+10,width=60,height=30) win.mainloop()
十、鼠标键盘事件处理
1、鼠标事件
鼠标相关事件及其含义:
<Button-1> 单击鼠标左键
<Button-2> 单击鼠标中间键
<Button-3> 单击鼠标右键
<Button-4> 向上滚动滑轮
<Button-5> 向下滚动滑轮
<B1-Motion> 按下鼠标左键并拖动鼠标
<B2-Motion> 按下鼠标中键并拖动鼠标
<B3-Motion> 按下鼠标右键并拖动鼠标
<ButtonRelease-1> 释放鼠标左键
<ButtonRelease-2> 释放鼠标中键
<ButtonRelease-3> 释放鼠标右键
<Double-Button-1> 双击鼠标左键
<Double-Button-2> 双击鼠标中键
<Double-Button-3> 双击鼠标右键
<Enter> 鼠标进入控件
<Leave> 鼠标移出控件
示例-鼠标移入移出控制文字显示:
from tkinter import * def show1(event): label.config(text="我是LABEL组件") def hidden1(event): label.config(text="") win = Tk() label = Label(win,bg="#C5E1EF",width=20,height=3) label.pack(pady=20,padx=20) label.bind("<Enter>",show1) label.bind("<Leave>",hidden1) win.mainloop()
示例-鼠标相关事件的使用:
from tkinter import * def click_mouse_left_key(event): label1.config(text="你点击了鼠标左键",fg="red") def click_mouse_middle_key(event): label2.config(text="你点击了鼠标中间键",fg="red") def click_mouse_right_key(event): label3.config(text="你点击了鼠标右键",fg="red") def move_mouse_right_key(event): label4.config(text="你拖动了鼠标左键",fg="red") def release_mouse_right_key(event): label5.config(text="你释放了鼠标左键",fg="red") def double_mouse_right_key(event): label6.config(text="你双击了鼠标左键",fg="red") win = Tk() label1 = Label(win,bg="#C5E1EF",width=20,height=3,text="点击鼠标左键") label1.grid(row=0,column=0,pady=20,padx=20) label1.bind("<Button-1>",click_mouse_left_key) label2 = Label(win,bg="#C5E1EF",width=20,height=3,text="点击鼠标中间键") label2.grid(row=0,column=1,pady=20,padx=20) label2.bind("<Button-2>",click_mouse_middle_key) label3 = Label(win,bg="#C5E1EF",width=20,height=3,text="点击鼠标右键") label3.grid(row=0,column=2,pady=20,padx=20) label3.bind("<Button-3>",click_mouse_right_key) label4 = Label(win,bg="#C5E1EF",width=20,height=3,text="按下鼠标左键并拖动") label4.grid(row=1,column=0,pady=20,padx=20) label4.bind("<B1-Motion>",move_mouse_right_key) label5 = Label(win,bg="#C5E1EF",width=20,height=3,text="按下鼠标左键并释放") label5.grid(row=1,column=1,pady=20,padx=20) label5.bind("<ButtonRelease-1>",release_mouse_right_key) label6 = Label(win,bg="#C5E1EF",width=20,height=3,text="双击鼠标左键") label6.grid(row=1,column=2,pady=20,padx=20) label6.bind("<Double-Button-1>",double_mouse_right_key) win.mainloop()
2、键盘事件
键盘事件的列表及其含义:
<Focusln> 键盘进入组件
<FocusOut> 键盘离开组件
<Key> 按下某键,键值会作为event对象参数被传递
<Shift-Up> 同时按住<Shift>和<Up>键
<Alt-Up> 同时按住<Alt>和<Up>键
<Control-Up> 同时按住<Control>和<Up>键
示例-输入文字时,统计多行文本框中的字数:
from tkinter import * def prt(event): le = len(text.get("0.0",END)) label.config(text=str(le)) win = Tk() text = Text(win,width=20,height=5) text.pack() label = Label(win) label.pack() text.bind("<Key>",prt) win.mainloop()
示例-贪吃蛇:
from tkinter import * w = 10 #蛇体由小正方形组成,w为正方形的边长 x1 = 0 #蛇头的初始位置 y1 = 10 num = 5 #初始状态的蛇由5个小正方形组成 step = 10 #蛇移动的单元距离 def xx(module): return int(module.winfo_geometry().split("+")[1]) def yy(module): return int(module.winfo_geometry().split("+")[2]) def up1(event): for index,ch in enumerate(snake): ind = len(snake)-index-1 if ind == 0: snake[ind].place(x=xx(snake[ind]),y=yy(snake[ind])-step) else: snake[ind].place(x=xx(snake[ind-1]), y=yy(snake[ind-1])) def down1(event): for index, ch in enumerate(snake): ind = len(snake) - index - 1 if ind == 0: snake[ind].place(x=xx(snake[ind]), y=yy(snake[ind]) + step) else: snake[ind].place(x=xx(snake[ind - 1]), y=yy(snake[ind - 1])) def right1(event): for index, ch in enumerate(snake): ind = len(snake) - index - 1 if ind == 0: snake[ind].place(x=xx(snake[ind])+step, y=yy(snake[ind])) else: snake[ind].place(x=xx(snake[ind - 1]), y=yy(snake[ind - 1])) def left1(event): for index, ch in enumerate(snake): ind = len(snake) - index - 1 if ind == 0: snake[ind].place(x=xx(snake[ind])-step, y=yy(snake[ind])) else: snake[ind].place(x=xx(snake[ind - 1]), y=yy(snake[ind - 1])) win = Tk() snake = [] for i in range(num): item1 = Frame(width=10,height=10,bg="black") snake.append(item1) item1.place(x=x1,y=y1+i*w) snake[0].config(bg="red") win.bind("<Up>",up1) win.bind("<Down>",down1) win.bind("<Left>",left1) win.bind("<Right>",right1) win.mainloop()
3、绑定多个事件处理程序:
示例-绑定多个事件:
from tkinter import * def fg1(): button.config(fg="red") def bg1(event): button.config(bg="blue") def font1(event): button.config(font=14) win = Tk() button = Button(win,text="这是个按钮",command=fg1) button.bind("<Button-1>",bg1,add="+") button.bind("<Button-1>",font1,add="+") button.pack(pady=10) win.mainloop()
如果不用add="+"参数,最后一次绑定的事件会替代前面的所有事件。
可以用label.unbind("<Button-1>")取消绑定。
示例-方块只能在窗口内移动:
from tkinter import * step = 5 def up1(event): print(f"X:{xx(frame)},Y:{yy(frame)}") # 如果组件贴着窗口的上边缘,则取消绑定键盘事件 if yy(frame) <= 0: win.unbind("<Up>") else: frame.place(x=xx(frame), y=yy(frame) - step) def down1(event): print(f"X:{xx(frame)},Y:{yy(frame)}") #如果组件贴着窗口的下边缘,则取消绑定键盘事件 if yy(frame) >= 160: win.unbind("<Down>") else: frame.place(x=xx(frame),y=yy(frame)+step) def left1(event): print(f"X:{xx(frame)},Y:{yy(frame)}") if xx(frame) <= 0: win.unbind("<Left>") else: frame.place(x=xx(frame)-step, y=yy(frame)) def right1(event): print(f"X:{xx(frame)},Y:{yy(frame)}") if xx(frame) >= 260: win.unbind("<Right>") else: frame.place(x=xx(frame) + step, y=yy(frame)) def xx(moudle): return int(moudle.winfo_geometry().split("+")[1]) def yy(moudle): return int(moudle.winfo_geometry().split("+")[2]) win = Tk() win.geometry("300x200") win.resizable(0,0) frame = Frame(width=40,height=40,bg="#E2ABE5") frame.place(x=0,y=0) win.bind("<Up>",up1) win.bind("<Down>",down1) win.bind("<Left>",left1) win.bind("<Right>",right1) win.mainloop()
示例-查看颜色小游戏:
from tkinter import * import random num = 1 #第多少关 inde = random.randint(0,99) #随机设置与众不同的方块(方块A) #随机设置颜色 def col(): arr = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"] #为保证颜色相近,color1+color2为多数方块的颜色;color1+color3为方块A的颜色 color1 = "" color2 = "" color3 = "" for i in range(4): color1 += arr[random.randint(0,len(arr)-1)] for i in range(2): color2 += arr[random.randint(0,len(arr)-1)] for i in range(2): color3 += arr[random.randint(0,len(arr)-1)] colorArr = [] #将两种颜色保存到列表 colorArr.append("#"+color1+color2) colorArr.append("#"+color1+color3) return colorArr def panduan(event): global num global inde num += 1 #当前游戏关数 level.config(text=f"第{num}关") sqareBox[inde].config(text="") #清除上次的提示信息 sqareBox[inde].unbind("<Button-1>") #取消上一次的事件绑定 inde = random.randint(0,99) #重新重成方块A colorBox = col() #print(colorBox,inde+1) #可以打印出两个颜色代码和方块A所在的位置 for i in sqareBox: i.config(bg=colorBox[0]) sqareBox[inde].config(bg=colorBox[1]) sqareBox[inde].bind("<Button-1>",panduan) #重新为方块A绑定单击事件 def tishi(event): sqareBox[inde].config(text="here") win = Tk() win.geometry("270x310") win.resizable(0,0) sqareBox = [] #将方块存储在列表中 colorBox = col() for i in range(10): #行 for j in range(10): #列 label = Label(win,width=3,height=1,bg=colorBox[0],relief="groove") sqareBox.append(label) label.grid(row=i,column=j) sqareBox[inde].config(bg=colorBox[1]) sqareBox[inde].bind("<Button-1>",panduan) #为颜色与众不同的方块添加事件 level = Label(win,text="第1关",font=14) level.grid(row=11,column=0,columnspan=10,pady=10) que = Button(win,text="提示一下下",font=14) que.bind("<Button-1>",tishi) que.grid(row=12,column=0,columnspan=10,pady=10) win.mainloop()
示例-一键着色:
from tkinter import * import random # 随机生成颜色 def col(): arr=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"] color1="#" for i in range(6): color1+=arr[random.randint(0,15)] return color1 # 第一部分Label组件添加颜色 def go1(): a=col() for i in box1: i.config(bg=a) # 第二部分Label组件添加颜色 def go2(event): a=col() for i in box2: i.config(bg=a) win=Tk() win.geometry("330x200") box1=[] box2=[] # 通过循环定义多个Label组件 for i in range(8): for j in range(2): label=Label(win,width=5,height=1,relief="groove") label.grid(row=j,column=i) if (i+j)%2==0: box1.append(label) else: box2.append(label) btn=Button(win,text="一键着色",command=go1) btn.grid(row=9,column=0,columnspan=8) btn.bind("<Button-1>",go2,add="+") #绑定第二个事件 win.mainloop()
十一、综合案例-滚动大抽奖:
from tkinter import * import random def comeon(): global timer,temp i = random.randint(0,len(box)-1) temp = box[i] canvas.itemconfigure(re,text=temp) timer = win.after(100,comeon) def callback(event): global timer,boo,re3,box,i,temp if not boo: comeon() boo = True else: timer = win.after_cancel(timer) box.remove(temp) boo = False win = Tk() win.geometry("380x270") bg_img = PhotoImage(file="bg.png") btn_img = PhotoImage(file="button.png") canvas = Canvas(win,width=380,height=270) canvas.pack() temp = "" timer = "" boo = False bg = canvas.create_image(190,135,image=bg_img) btn = canvas.create_image(190,215,image=btn_img) re = canvas.create_text(190,110,text="",font="宋体 16 bold") canvas.tag_bind(btn,"<Button-1>",callback) with open("all.txt","r",encoding="utf-8") as f: box = f.readlines() win.mainloop()
after()方法类型于定时器,可以实现每间隔一段时间调用一次方法;而要让动画停下来就必须先清除定时器,清除定时器的方法为after_cancel()
十二、综合案例-音乐机器人

from tkinter import * from tkinter.messagebox import * import winsound import random def count(): global tim,countdown cav.delete(text) entry.destroy() cav.itemconfig(showTime,image=imgbox[tim + 1]) tim -= 1 countdown = win.after(1000,count) #定时哭器,第过1000毫秒就调用一次count if tim < 0: win.after_cancel(countdown) play() def start(event): global tim,showTime tim = time1.get() if tim != "" and tim in ["0","1","2","3","4","5","6","7","8","9"]: tim = int(tim) else: showerror("错误提示","请输入0到9之间的数字!") return showTime = cav.create_image(958,228) if tim > 0 and tim < 10: count() elif tim == 0: cav.delete(text) entry.destroy() play() def play(): cav.itemconfigure(showTime,image=imgbox[-1]) cav.tag_bind(showTime,"<Button-1>",quitwin) music = ["m1.wav","m2.wav","m3.wav","m4.wav","m5.wav","m6.wav",] one = "wav/"+random.choice(music) winsound.PlaySound(one,winsound.SND_ASYNC) def quitwin(event): win.quit() win =Tk() win.geometry("1920x1080+0+0") win.state("zoomed") win.title("音乐机器人") imgbox = [] #倒计时数字图片对象 for i in range(0,11): img = PhotoImage(file="image/bg"+str(i)+".png") imgbox.append(img) quit1 = PhotoImage(file="image/quit.png") imgbox.append(quit1) pao = PhotoImage(file="image/pao.png") #实现窗口布局: cav = Canvas(win,width=1920,height=1080,bg="yellow") cav.place(x=0,y=0,relwidth=1,relheight=1) bg = cav.create_image(960,530,image=imgbox[0]) #用于倒计时显示: text = cav.create_image(470,280,image=pao) time1 = StringVar() entry = Entry(win,textvariable=time1,font=("宋体",20,"normal"),relief="groove",bd=2) entry.place(x=400,y=240,width=110,height=40) #当变量发生变化时调用start()方法: entry.bind("<Return>",start) win.mainloop()
十三、九宫格切图器

import tkinter as tk from PIL import Image,ImageTk import tkinter.filedialog import tkinter.messagebox def select_button(): global a,img fileType = [("jpg文件","*.jpg"),("png文件","*.png")] a = tk.filedialog.askopenfilename(title="选择图片",filetypes=fileType) img = Image.open(a) image_width = img.size[0] #获取原图片的宽度 image_height = img.size[1] #获取原图片的高度 if image_width > image_height: #如果原图片的宽度大于高度,那么设置预览图的宽度为310,高度等比例缩小 image_height = int(image_height * 310 / image_width) image_width = 310 else: #如果原图的高度大于宽度,那么设置预览图的高度为280,宽度等比例缩小 image_width = int(image_width * 280 / image_height) image_height = 280 out = img.resize((image_width,image_height)) img = ImageTk.PhotoImage(out) label_image.config(image=img) label_image.place(x=120,y=80) txt.set(a) #将图片路径显示在文本框中 def cut_image(image): width,height = image.size colWidth = int(width / 3) #一行三张 colHeight = int(height / 3) image_grid = [] for i in range(0,3): for j in range(0,3): row = (j*colWidth,i*colHeight,(j+1)*colWidth,(i+1)*colWidth) image_grid.append(row) image_list = [image.crop(row) for row in image_grid] return image_list def save_images(image_list): index = 1 for image in image_list: image.save(str(index)+".png","PNG") index += 1 def cut_button(): file_path = txt.get() if file_path == "": tk.messagebox.showerror("错误提供","所选文件为空,请重新选择文件!") else: image = Image.open(file_path) image_list = cut_image(image) save_images(image_list) tk.messagebox.showinfo("切图成功","切图成功,请在程序所在目录查看") main =tk.Tk() main.configure(bg="#F2F1D7") main.geometry("550x400") main.title("九宫格切图器") label1 = tk.Label(main,text="选择文件:",font=("bold",14),fg="#f00",bg="#F2F1D7") label1.place(x=20,y=25) txt = tk.StringVar() txt_entry = tk.Entry(main,width=55,textvariable=txt,relief=tk.GROOVE) txt_entry.place(x=120,y=20,width=220,height=30) button1 = tk.Button(main,text="浏览",fg="#f00",bg="#E8FFE8",font=14,command=select_button,relief=tk.GROOVE) button1.place(x=350,y=20,width=60,height=32) button2 = tk.Button(main,text="我选好了",fg="#f00",bg="#DDF3FF",font=13,relief=tk.GROOVE,command=cut_button) button2.place(x=430,y=20,width=90,height=32) label_image = tk.Label(main,bg="#F2F1D7") main.mainloop()
十四、模拟斗地主发牌

from tkinter import * from tkinter.messagebox import * import random from PIL import Image,ImageTk,ImageSequence class poker(): def __init__(self): self.win = Tk() self.win.geometry("1000x500-200-200") self.win.title("斗地主") self.pkBox_num = [] #所有扑克编号 self.pkBox = [] self.moveCenter = True self.pb = [] #底牌 self.pb_box = [] #玩家手里的底牌 self.pb_num = [] #底牌编号 self.pb1_num = [] #左边玩家牌的编号 self.pb2_num = [] #右边玩家牌的编号 self.pb3_num = [] #中间玩家牌的编号 self.pbback = [] #发牌时显示牌背面 self.temp = 0 #所发出去的牌的数量 self.backbox = [] #将绘制的扑克背面存储在此列表中 self.boo = 0 #判断谁是地主,0表示没人叫地主,1表示左侧玩家、2表示中间玩家、3表示右侧玩家 self.imgback1 = Image.open("border/back.png") #牌的背面 self.imgback2 = self.imgback1.resize((70,120)) #设置扑克牌大小 for i in range(1,55): self.img1 = Image.open("border/"+str(i)+".png") self.img2 = self.img1.resize((70,120)) self.img = ImageTk.PhotoImage(self.img2) self.pkBox.append(self.img) self.imgback = ImageTk.PhotoImage(self.imgback2) ##牌的背面图片对象 self.p1 = PhotoImage(file="border/people1.png") self.p2 = PhotoImage(file="border/people2.png") self.p3 = PhotoImage(file="border/people3.png") self.p4 = PhotoImage(file="border/people4.png") self.canvas = Canvas(self.win,bg="#DDF3FF") self.canvas.place(x=0,y=0,width=1000,height=500) #左侧的叫地主按钮: self.call1 = Button(self.win,text="叫地主",command=lambda: self.dizhu(1),wraplength=20,bg="#efefda",relief="groove") #中间的叫地主按钮: self.call2 = Button(self.win, text="叫地主", command=lambda: self.dizhu(2),bg="#efefda",relief="groove") #右侧的叫地主按钮: self.call3 = Button(self.win, text="叫地主", command=lambda: self.dizhu(3), wraplength=20, bg="#efefda",relief="groove") self.dizhubox = [self.call1,self.call2,self.call3] self.btn1 = Button(self.win,text="发牌",command=self.fapai,relief="groove",bg="#E8E8FF") self.btn2 = Button(self.win, text="码牌", command=self.mapai, relief="groove", bg="#bdbdec") self.btn3 = Button(self.win, text="重新开始", command=self.reset, relief="groove", bg="#66cccc") self.btn1.place(x=360,y=180,width=80,height=30) self.btn2.place(x=500, y=180, width=80, height=30) self.btn3.place(x=400, y=230, width=150, height=30) self.reset() self.win.mainloop() def dizhu(self,who): if who == 1: self.canvas.itemconfig(self.left,image=self.p1) elif who == 2: self.canvas.itemconfig(self.center,image=self.p1) self.moveCenter = False elif who == 3: self.canvas.itemconfig(self.right,image=self.p2) self.boo = who for it in self.dizhubox: it.place_forget() def fapai(self): if self.boo == 0: showerror("错误", "请先确定地主") return False a = random.randint(0, len(self.pkBox) - 1) if (a not in self.pb2_num) and (a not in self.pb3_num) and (a not in self.pb1_num): if self.temp % 3 == 0: lt = self.canvas.create_image(150, 70 + self.temp // 3 * 20, image=self.pkBox[a]) self.pb1_num.append(a) self.pb_box.append(lt) elif self.temp % 3 == 1: rt = self.canvas.create_image(335 + self.temp // 3 * 20, 400, image=self.pkBox[a]) self.pb2_num.append(a) self.pb_box.append(rt) else: ct = self.canvas.create_image(770, 70 + self.temp // 3 * 20, image=self.pkBox[a]) self.pb3_num.append(a) self.pb_box.append(ct) self.pb.remove(a) self.canvas.delete(self.backbox[-1]) del self.backbox[-1] else: self.temp -= 1 self.temp += 1 if self.temp < len(self.pkBox) - 3: self.win.after(30, self.fapai) else: self.canvas.create_image(360, 100, image=self.pkBox[self.pb[0]]) self.canvas.create_image(460, 100, image=self.pkBox[self.pb[1]]) self.canvas.create_image(560, 100, image=self.pkBox[self.pb[2]]) for i in self.backbox: self.canvas.delete(self.backbox[-1]) del self.backbox[-1] self.canvas.delete(self.backbox[-1]) del self.backbox[-1] print(len(self.backbox)) def mapai(self): self.btn2.config(state="disabled") # self.canvas.delete("all") for it in self.pb_box: self.canvas.delete(it) self.pb_box.remove(it) if self.boo == 1: self.pb1_num.extend(self.pb) elif self.boo == 2: self.pb2_num.extend(self.pb) else: self.pb3_num.extend(self.pb) self.pb1_num.sort() self.pb2_num.sort() self.pb3_num.sort() for i in range(len(self.pb1_num)): self.canvas.create_image(150, 70 + i * 20, image=self.pkBox[self.pb1_num[i]]) for i in range(len(self.pb3_num)): self.canvas.create_image(770, 70 + i * 20, image=self.pkBox[self.pb3_num[i]]) if self.moveCenter: for i in range(len(self.pb2_num)): self.canvas.create_image(335 + i * 20, 400, image=self.pkBox[self.pb2_num[i]]) else: for i in range(len(self.pb2_num)): self.canvas.create_image(310 + i * 20, 400, image=self.pkBox[self.pb2_num[i]]) def reset(self): self.temp = 0 self.canvas.delete("all") self.pb = [] self.boo = 0 self.pb1_num = [] self.pb2_num = [] self.pb3_num = [] self.moveLeft = True self.left = self.canvas.create_image(70,80,image=self.p3) self.right = self.canvas.create_image(850, 80, image=self.p4) self.center = self.canvas.create_image(225, 400, image=self.p3) for it in self.dizhubox: it.config(state="normal") for i in range(54): self.back1 = self.canvas.create_image(160 + i * 11, 90, image=self.imgback) self.backbox.append(self.back1) self.pb.append(i) self.call1.place(x=275, y=160, width=30, height=100) # 左侧的叫地主 self.call2.place(x=415, y=290, width=120, height=30) # 中间的叫地主 self.call3.place(x=650, y=160, width=30, height=100) # 右侧的叫地主 if __name__ == "__main__": poker()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)