【Python】GUI编程(Tkinter)教程
什么是Tkinter?
Tkinter 是 Python 的标准 GUI 库。Python 使用 Tkinter 可以快速的创建 GUI 应用程序。
由于 Tkinter 是内置到 python 的安装包中、只要安装好 Python 之后就能 import Tkinter 库、而且 IDLE 也是用 Tkinter 编写而成、对于简单的图形界面 Tkinter 还是能应付自如。
使用
导入
import tkinter
注意:Python3.x 版本使用的库名为 tkinter,即首写字母 T 为小写。
创建一个GUI程序
- 1、导入 Tkinter 模块
- 2、创建控件
- 3、指定这个控件的 master, 即这个控件属于哪一个
- 4、告诉 GM(geometry manager) 有一个控件产生了。
#!/usr/bin/python3 import tkinter top = tkinter.Tk() # 进入消息循环 top.mainloop()
窗口主体框架
每一个 tkinter 应用的主体框架都可以包含下面这部分. 定义 window
窗口 和 window
的一些属性, 然后书写窗口内容, 最后执行window.mainloop
让窗口活起来.
import tkinter as tk window = tk.Tk() window.title(\'my window\') window.geometry(\'500x500\')
#注意:这里的乘是×不是* # 这里是窗口的内容 window.mainloop()
窗口内容
Label & Button 标签和按钮
这次我们会建立一个用来描述的标签 tk.Label
, 比如:
import tkinter as tk #创建窗口 window=tk.Tk() window.title(\'Mywindow\')#窗口的标题 window.geometry(\'200x100\')#窗口的大小 #定义一个label l = tk.Label(window, text=\'Hi! this is TK!\', # 标签的文字 bg=\'green\', # 标签背景颜色 font=(\'Arial\', 12), # 字体和字体大小 width=15, height=2 # 标签长宽(以字符长度计算) ) l.pack() # 固定窗口位置 window.mainloop()
关于Label的更多内容可以看这里https://www.runoob.com/python/python-tk-label.html
我们也可以通过变量的形式控制标签的显示, 这时我们引入按钮 tk.Button
的概念, 没点一次按钮, 标签变化一次. 用一下内容替换上面的标签. 并把需要变化的文字存成变量 var
:
var = tk.StringVar() # 这时文字变量储存器 l = tk.Label(window, textvariable=var, # 使用 textvariable 替换 text, 因为这个可以变化 bg=\'green\', font=(\'Arial\', 12), width=15, height=2) l.pack()
接着我们来做 按钮 tk.Button
:
b = tk.Button(window, text=\'hit me\', # 显示在按钮上的文字 width=15, height=2, command=hit_me) # 点击按钮式执行的命令 b.pack() # 按钮位置
那么点击是的命令我们用 if
else
语句来判断. 用 on_hit
来判断当前状态.
on_hit = False # 默认初始状态为 False def hit_me(): global on_hit if on_hit == False: # 从 False 状态变成 True 状态 on_hit = True var.set(\'you hit me\') # 设置标签的文字为 \'you hit me\' else: # 从 True 状态变成 False 状态 on_hit = False var.set(\'\') # 设置 文字为空
完整代码:
import tkinter as tk #创建窗口 window=tk.Tk() window.title(\'Mywindow\')#窗口的标题 window.geometry(\'200x100\')#窗口的大小 #定义一个label var=tk.StringVar()#定义一个字符串变量 l = tk.Label(window, textvariable=var, # 标签的文字 bg=\'green\', # 标签背景颜色 font=(\'Arial\', 12), # 字体和字体大小 width=15, height=2 # 标签长宽 ) l.pack() # 固定窗口位置 #定义一个全局变量,来表明字符显示与不显示 on_hit=False #按钮的函数 def hit_me(): global on_hit#声明全局变量 if on_hit==False: on_hit=True var.set(\'You hit me!\') else: on_hit=False var.set(\'\') #按钮 b=tk.Button(window,text=\'点我\',width=15,height=2,command=hit_me)#点击按钮执行一个名为“hit_me”的函数 b.pack() window.mainloop()
没有点击时:
点击第一次:
点击第二次:
Entry & Text 输入, 文本框
窗口主体框架
每一个tkinter应用的主体框架都包含以下几部分:
- 主窗口:
window
,及主窗口的一些基本属性(标题、大小) - 让窗口活起来:
window.mainloop()
import tkinter as tk window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') ##显示出来 window.mainloop()
窗口内容(窗口上的控件)
创建按钮分别触发两种情况
b1 = tk.Button(window,text="insert point",width=15,height=2,command=insert_point) b1.pack() b2 = tk.Button(window,text="insert end",command=insert_end) b2.pack()
创建输入框entry,用户输入任何内容都显示为*
e = tk.Entry(window,show=\'*\') e.pack()
创建一个文本框用于显示
t = tk.Text(window,height=2)
t.pack()
定义触发事件时的函数(注意:因为Python的执行顺序是从上往下,所以函数一定要放在按钮的上面)
def insert_point(): var = e.get() t.insert(\'insert\',var) def insert_end(): var = e.get() t.insert(\'end\',var)
完整代码:
import tkinter as tk window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') #定义一个输入框entry e=tk.Entry(window,show=None)#如果是输入密码,可以写show=\'*\' e.pack() #定义按钮功能 def insert_point(): var=e.get() t.insert(\'insert\',var) def insert_end(): var=e.get() t.insert(\'end\',var)#这里还可以定义字符串插入的具体位置,比如t.insert(\'1.1\',var),表示插入到第一行第一列
#定义2个按钮 Button b1 = tk.Button(window,text="insert point",width=15,height=2,command=insert_point) b1.pack() b2 = tk.Button(window,text="insert end",command=insert_end) b2.pack() #定义一个文本框 Text t=tk.Text(window,height=2) t.pack() ##显示出来 window.mainloop()
窗口界面
测试一下
第一次:在entry中输入tkinter
,在text中输入0000
并将光标定位在中间位置,点击insert point
第二次:点击insert end
Listbox 列表部件
创建主窗口
import tkinter as tk window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') ##显示出来 window.mainloop()
创建一个label用于显示
var1 = tk.StringVar() #创建变量 l =tk.Label(window,bg=\'yellow\',width=4,textvariable=var1) l.pack()
创建一个方法用于按钮的点击事件
def print_selection(): value = lb.get(lb.curselection()) #获取当前选中的文本 var1.set(value) #为label设置值
创建一个按钮
b1 = tk.Button(window, text=\'print selection\', width=15, height=2, command=print_selection) b1.pack()
创建一个Listbox和变量var2,并将var2的值赋给Listbox
var2 = tk.StringVar() var2.set((11,22,33,44)) #为变量设置值 #创建Listbox lb = tk.Listbox(window, listvariable=var2) #将var2的值赋给Listbox #创建一个list并将值循环添加到Listbox控件中 list_items = [1,2,3,4] for item in list_items: lb.insert(\'end\', item) #从最后一个位置开始加入值 lb.insert(1, \'first\') #在第一个位置加入\'first\'字符 lb.insert(2, \'second\') #在第二个位置加入\'second\'字符 lb.delete(2) #删除第二个位置的字符 lb.pack()
完整代码:
import tkinter as tk window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') #创建一个lable var1 = tk.StringVar() #创建变量 l =tk.Label(window,bg=\'yellow\',width=4,textvariable=var1) l.pack() #按钮事件 def print_selection(): value = lb.get(lb.curselection()) #获取当前选中的文本 var1.set(value) #为label设置值 #创建一个按钮 b1 = tk.Button(window, text=\'print selection\', width=15, height=2, command=print_selection) b1.pack() #创建一个Listbox和变量var2,并将var2的值赋给Listbox var2 = tk.StringVar() var2.set((11,22,33,44)) #为变量设置值 #创建Listbox lb = tk.Listbox(window, listvariable=var2) #将var2的值赋给Listbox #创建一个list并将值循环添加到Listbox控件中 list_items = [1,2,3,4]#定义列表 for item in list_items: lb.insert(\'end\', item) #从最后一个位置开始加入值 lb.insert(1, \'first\') #在第一个位置加入\'first\'字符 lb.insert(2, \'second\') #在第二个位置加入\'second\'字符 lb.delete(2) #删除第二个位置的字符 lb.pack() ##显示出来 window.mainloop()
演示
Radiobutton 选择按钮
这一次的效果将会像下面的图片一样.
如果选择了某个选项, 效果就会如下.
radiobutton 部件
首先我们需要定义一个 var
用来将 radiobutton 的值和 Label 的值联系在一起. 然后创建一个radiobutton部分:
var = tk.StringVar() l = tk.Label(window, bg=\'yellow\', width=20, text=\'empty\') l.pack() r1 = tk.Radiobutton(window, text=\'Option A\', variable=var, value=\'A\', command=print_selection) r1.pack()
其中variable=var
, value=\'A\'
的意思就是,当我们鼠标选中了其中一个选项,把value的值A
放到变量var中,然后赋值给variable
触发功能
我们将定义一个功能, 用来对选择的 radiobutton 进行操作. print_selection
功能就是选择了某个 radiobutton 后我们会在屏幕上打印的选项.
def print_selection(): l.config(text=\'you have selected \' + var.get())
当触发这个函数功能时,我们的 label
中就会显示 text
所赋值的字符串即 ‘you have selected’, 后面则是我们所选中的选项 var.get()
就是获取到变量 var
的值, 举个例子就是我们一开始所做的将选项 “option A” 选中时的值以 “A” 放入 var
中, 所以获取的也就是A 即如果我们这时候选中 “option A” 选项,label显示的值则是 “you have selected A”.
完整代码:
import tkinter as tk window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') #创建一个lable var= tk.StringVar() #创建变量 l =tk.Label(window,bg=\'yellow\',width=20,height=2,text=\'empty\') l.pack() #实现将选择的选项显示在lable def print_selection(): l.config(text=\'you have selected\'+var.get()) #创建几个Radiobutton r1 = tk.Radiobutton(window, text=\'Option A\', variable=var, value=\'A\', command=print_selection) r1.pack() r2 = tk.Radiobutton(window, text=\'Option B\', variable=var, value=\'B\', command=print_selection) r2.pack() r3 = tk.Radiobutton(window, text=\'Option C\', variable=var, value=\'C\', command=print_selection) r3.pack() ##显示出来 window.mainloop()
演示:
Scale 尺度
这一次的效果将会像下面的图片一样.
如果拖动滚动条, 效果就会如下.
scale 部件
s = tk.Scale(window, label=\'try me\', from_=5, to=11, orient=tk.HORIZONTAL, length=200, showvalue=0, tickinterval=2, resolution=0.01, command=print_selection) s.pack()
这里的参数label
是指scale部件的名称,即在这里scale部件名称为try me
- 参数
from_=5,to=11
的意思就是从5到11,即这个滚动条最小值为5,最大值为11(这里使用from_是因为在python中有from这个关键词) - 参数
orient=tk.HORIZONTAL
在这里就是设置滚动条的方向,如我们所看到的效果图,这里HORIZONTAL
就是横向。 - 参数
length
这里是指滚动条部件的长度,但注意的是和其他部件width表示不同,width表示的是以字符为单位,比如width=4
,就是4个字符的长度,而此处的length=200
,是指我们常用的像素为单位,即长度为200个像素 - 参数
resolution=0.01
这里我们可以借助数学题来理解,我们做的很多数学题都会让我们来保留几位小数,此处的0.01就是保留2位小数,即效果图中的5.00 9.00等等后面的两位小数,如果保留一位就是resolution=0.1
这里的showvalue
就是设置在滚动条上方的显示。showvalue=0
显示的就是效果图,上方无结果显示,如果改为showvalue=1
,则会显示为:
参数tickinterval
设置的就是坐标的间隔,此处为tickinterval=2
,显示的即为效果图中的5.00 7.00 9.00 11.00 如果改为tickinterval=3
则为5.00 8.00 11.00:
触发功能
l = tk.Label(window, bg=\'yellow\', width=20, text=\'empty\') l.pack() def print_selection(v): l.config(text=\'you have selected \' + v)
这里相比前面多了参数v
,这里的参数v
即将滚动条定位的数据,即如效果图中最开始,定位到5.00,label
中显示you have selected 5.00
完整代码:
import tkinter as tk window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') #创建一个label l =tk.Label(window,bg=\'yellow\',width=20,height=2,text=\'empty\') l.pack() #实现将选择的选项显示在lable def print_selection(v): l.config(text=\'you have selected\'+v) #创建一个Scale s=tk.Scale(window,label=\'Try me\',from_=5,to=11,orient=tk.HORIZONTAL, length=200,showvalue=1,tickinterval=3,resolution=0.01,command=print_selection) s.pack() ##显示出来 window.mainloop()
Checkbutton 勾选项
运行之后的效果将会像下面的图片一样,此时不作任何操作.
如果只选中第一个选项,即图中的python, 效果就会如下.
如果只选中第二个选项,即图中的c++, 效果就会如下.
如果两个选项都选中, 效果就会如下.
如果两个选项都不选中, 效果就会如下.
Checkbutton部件
var1 = tk.IntVar() c1 = tk.Checkbutton(window, text=\'Python\', variable=var1, onvalue=1, offvalue=0, command=print_selection) c1.pack()
参数onvalue
和前面讲的部件radiobutton
中的value相似, 当我们选中了这个checkbutton,onvalue
的值1就会放入到var1
中, 然后var1将其赋值给参数variable
,offvalue
用法相似,但是offvalue
是在没有选中这个checkbutton时,offvalue
的值1放入var1,然后赋值给参数variable
这是创建一个checkbutton部件,以此类推,可以创建多个checkbutton
触发功能
def print_selection(): if (var1.get() == 1) & (var2.get() == 0): #如果选中第一个选项,未选中第二个选项 l.config(text=\'I love only Python \') elif (var1.get() == 0) & (var2.get() == 1): #如果选中第二个选项,未选中第一个选项 l.config(text=\'I love only C++\') elif (var1.get() == 0) & (var2.get() == 0): #如果两个选项都未选中 l.config(text=\'I do not love either\') else: l.config(text=\'I love both\') #如果两个选项都选中
相对于前面学过的 print_selection
,这一段比较长,其实功能差不多,只不过加了if...elif...else
来选择控制而已即如代码注释,config
在前面已经讲过就是将参数text
的值显示,这里的var1.get() == 1
就是前面所说的var1获得的变量onvalue=1
,var1.get() == 0
即是var1
获得的变量offvalu=0
同理var2
也是如此。
完整代码:
import tkinter as tk window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') #创建一个lable l =tk.Label(window,bg=\'yellow\',width=20,height=2,text=\'empty\') l.pack() #实现将选择的选项显示在lable def print_selection(): if (var1.get() == 1) & (var2.get() == 0): #如果选中第一个选项,未选中第二个选项 l.config(text=\'I love only Python \') elif (var1.get() == 0) & (var2.get() == 1): #如果选中第二个选项,未选中第一个选项 l.config(text=\'I love only C++\') elif (var1.get() == 0) & (var2.get() == 0): #如果两个选项都未选中 l.config(text=\'I do not love anything\') else: l.config(text=\'I love both\') #如果两个选项都选中 var1=tk.IntVar() var2=tk.IntVar() #创建2个cheakButton cl=tk.Checkbutton(window,text=\'Python\',variable=var1,onvalue=1,offvalue=0,command=print_selection) cl.pack() c2=tk.Checkbutton(window,text=\'C++\',variable=var2,onvalue=1,offvalue=0,command=print_selection) c2.pack() ##显示出来 window.mainloop()
演示:
Canvas 画布
运行之后的效果将会像下面的图片一样.
如果点击move这个button, 效果就会如下.
Canvas部件
canvas = tk.Canvas(window, bg=\'blue\', height=100, width=200) canvas.pack()
这里的参数和以往学过的部件一样,所以就不再一一解释。 如果你想下载那个 instagram 的图标, 可以点击这里下载, 或者直接右键保存下面的图像.
image_file = tk.PhotoImage(file=\'ins.gif\') image = canvas.create_image(10, 10, anchor=\'nw\', image=image_file)
这里的代码主要是实现我们最终看到的在左上角的那张小图片。 image_file = tk.PhotoImage(file=\'ins.gif\')
这一句是创造一个变量存放ins.gif
这张图片。 image = canvas.create_image(10, 10, anchor=\'nw\', image=image_file)
里面的参数10,10
就是图片放入画布的坐标, 而这里的anchor=nw
则是把图片的左上角作为锚定点,在加上刚刚给的坐标位置,即可将图片位置确定。 最后一个参数的意思大家应该都知道,就是将刚刚存入的图片变量,赋值给image
。
x0, y0, x1, y1= 50, 50, 80, 80
line = canvas.create_line(x0, y0, x1, y1)
这段代码主要实现的是画一条直线,后面()
中给的参数就是线段两点的坐标,两点确定一条直线。此处给的就是从坐标(50,50)到(80,80)画一条直线。
oval = canvas.create_oval(x0, y0, x1, y1, fill=\'red\') #创建一个圆,填充色为`red`红色 arc = canvas.create_arc(x0+30, y0+30, x1+30, y1+30, start=0, extent=180) #创建一个扇形 rect = canvas.create_rectangle(100, 30, 100+20, 30+20) #创建一个矩形
这里面就是创建扇形时多了两个没见过的参数start=0
和extent=180
,其实就是从0度到180度,就好像扇子的边打开一样。在我们看来就是个半圆, 如果改为extent=90
,我们看到的就是一个1/4圆
触发功能
def moveit(): canvas.move(rect, 0, 2)
这里的触发不再是以往的print_selection了,哈哈,那么这里的是怎么样的功能呢,首先我们从单词理解来看就是移动的函数,在视频中也演示过了, 就是我们每点一次button
矩形就会移动这里canvas.move(rect, 0, 2)
的参数(rect,0,2)
就是移动rect
这个变量,即我们看到的矩形 后面的0和2,也就是横坐标移动0个单位,纵坐标移动2个单位,简单的说就是每次点击,横向不动,纵向移动两个单位。
完整代码:
import tkinter as tk window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') #新建画布 #显示图片 canvas=tk.Canvas(window,bg=\'blue\',height=100,width=200) image_file=tk.PhotoImage(file=\'ins.gif\') image=canvas.create_image(0,0,anchor=\'nw\',image=image_file) #画线 x0,y0,x1,y1=50,50,80,80 line=canvas.create_line(x0,y0,x1,y1) #画⚪ oval=canvas.create_oval(x0,y0,x1,y1,fill=\'red\') #画一个扇形 arc = canvas.create_arc(x0+30, y0+30, x1+30, y1+30, start=0, extent=90) #画一个矩形 rect = canvas.create_rectangle(100, 30, 100+20, 30+20) canvas.pack() def moveit(): canvas.move(rect,0,2) #创建一个Button b=tk.Button(window,text=\'Move\',command=moveit) b.pack() ##显示出来 window.mainloop()
演示:
Menubar 菜单
这一次的效果将会像下面的图片一样.
注意这里的操作系统是苹果的 MacOS, 它的菜单栏位置和 Windows 的不一样.
menubar 部件
下面是我们制作整个菜单栏的流程, 我们先需要加入一个 Menubar 作为整体框架, 然后再在 Menubar 中加一些部件.
##创建一个菜单栏,这里我们可以把他理解成一个容器,在窗口的上方 menubar = tk.Menu(window) ##定义一个空菜单单元 filemenu = tk.Menu(menubar, tearoff=0) ##将上面定义的空菜单命名为`File`,放在菜单栏中,就是装入那个容器中 menubar.add_cascade(label=\'File\', menu=filemenu) ##在`File`中加入`New`的小菜单,即我们平时看到的下拉菜单,每一个小菜单对应命令操作。 ##如果点击这些单元, 就会触发`do_job`的功能 filemenu.add_command(label=\'New\', command=do_job) filemenu.add_command(label=\'Open\', command=do_job)##同样的在`File`中加入`Open`小菜单 filemenu.add_command(label=\'Save\', command=do_job)##同样的在`File`中加入`Save`小菜单 filemenu.add_separator()##这里就是一条分割线 ##同样的在`File`中加入`Exit`小菜单,此处对应命令为`window.quit` filemenu.add_command(label=\'Exit\', command=window.quit)
同样的我们在定义另一个菜单Edit
也是如此和定义的File
菜单一样 这里再来看一下效果中比较不一样的菜单就是File
中的Import
菜单, 在这个菜单选项中, 我们还能分支出更多的选项.
submenu = tk.Menu(filemenu)##和上面定义菜单一样,不过此处实在`File`上创建一个空的菜单 filemenu.add_cascade(label=\'Import\', menu=submenu, underline=0)##给放入的菜单`submenu`命名为`Import` submenu.add_command(label="Submenu1", command=do_job)##这里和上面也一样,在`Import`中加入一个小菜单命令`Submenu1`
触发功能
counter = 0 def do_job(): global counter l.config(text=\'do \'+ str(counter)) counter+=1
这里的功能就是每触发一次命令,counter就会+1,在label上的显示就会从 do 0 ,do 1 , do 2…
完整代码:
import tkinter as tk window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') #新建一个label l=tk.Label(window,text=\'\',bg=\'yellow\') l.pack() #计数 counter = 0 def do_job(): global counter l.config(text=\'do \'+ str(counter)) counter+=1 #创建菜单 menubar=tk.Menu(window) #菜单一 filemenu=tk.Menu(menubar,tearoff=0) #一级菜单 menubar.add_cascade(label=\'File\',menu=filemenu) #二级菜单 filemenu.add_command(label=\'New\',command=do_job) filemenu.add_command(label=\'Open\',command=do_job) filemenu.add_separator()#分割线 filemenu.add_command(label=\'Exit\',command=window.quit) #菜单二 editmenu=tk.Menu(menubar,tearoff=0) #一级菜单 menubar.add_cascade(label=\'Edit\',menu=editmenu) #二级菜单 editmenu.add_command(label=\'Cut\',command=do_job) editmenu.add_command(label=\'Paste\',command=do_job) # #菜单一子菜单 submenu=tk.Menu(filemenu) #一级菜单 filemenu.add_cascade(label=\'Import\',menu=submenu,underline=0) #二级菜单 submenu.add_command(label=\'Submeau1\',command=do_job) submenu.add_command(label=\'Submeau1\',command=do_job) window.config(menu=menubar) ##显示出来 window.mainloop()
演示:
Frame 框架
这一次的效果将会像下面的图片一样.
Frame 部件
Frame 是一个在 Windows 上分离小区域的部件, 它能将 Windows 分成不同的区,然后存放不同的其他部件. 同时一个 Frame 上也能再分成两个 Frame, Frame 可以认为是一种容器.
###定义一个`label`显示`on the window` tk.Label(window, text=\'on the window\').pack() ###在`window`上创建一个`frame` frm = tk.Frame(window) frm.pack() ###在刚刚创建的`frame`上创建两个`frame`,我们可以把它理解成一个大容器里套了一个小容器,即`frm`上有两个`frame` ,`frm_l`和`frm_r` frm_l = tk.Frame(frm) frm_r = tk.Frame(frm) ###这里是控制小的`frm`部件在大的`frm`的相对位置,此处`frm_l`就是在`frm`的左边,`frm_r`在`frm`的右边 frm_l.pack(side=\'left\') frm_r.pack(side=\'right\') ###这里的三个label就是在我们创建的frame上定义的label部件,还是以容器理解,就是容器上贴了标签,来指明这个是什么,解释这个容器。 tk.Label(frm_l, text=\'on the frm_l1\').pack()##这个`label`长在`frm_l`上,显示为`on the frm_l1` tk.Label(frm_l, text=\'on the frm_l2\').pack()##这个`label`长在`frm_l`上,显示为`on the frm_l2` tk.Label(frm_r, text=\'on the frm_r1\').pack()##这个`label`长在`frm_r`上,显示为`on the frm_r1`
完整代码:
import tkinter as tk window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') ###定义一个`label`显示`on the window` tk.Label(window, text=\'on the window\').pack() ###在`window`上创建一个`frame` frm = tk.Frame(window,bg=\'green\') frm.pack() ###在刚刚创建的`frame`上创建两个`frame`,我们可以把它理解成一个大容器里套了一个小容器,即`frm`上有两个`frame` ,`frm_l`和`frm_r` frm_l = tk.Frame(frm,bg=\'red\') frm_r = tk.Frame(frm,bg=\'blue\') ###这里是控制小的`frm`部件在大的`frm`的相对位置,此处`frm_l`就是在`frm`的左边,`frm_r`在`frm`的右边 frm_l.pack(side=\'left\') frm_r.pack(side=\'right\') ###这里的三个label就是在我们创建的frame上定义的label部件,还是以容器理解,就是容器上贴了标签,来指明这个是什么,解释这个容器。 tk.Label(frm_l, text=\'on the frm_l1\',bg=\'red\').pack()##这个`label`长在`frm_l`上,显示为`on the frm_l1` tk.Label(frm_l, text=\'on the frm_l2\',bg=\'red\').pack()##这个`label`长在`frm_l`上,显示为`on the frm_l2` tk.Label(frm_r, text=\'on the frm_r1\',bg=\'blue\').pack()##这个`label`长在`frm_r`上,显示为`on the frm_r1` ##显示出来 window.mainloop()
演示:
messagebox 弹窗
其实这里的messagebox
就是我们平时看到的弹窗。 我们首先需要定义一个触发功能,来触发这个弹窗 这里我们就放上以前学过的button
按钮
tk.Button(window, text=\'hit me\', command=hit_me).pack()
通过触发功能,调用messagebox
def hit_me(): tk.messagebox.showinfo(title=\'Hi\', message=\'hahahaha\')
这里点击button
按钮就会弹出提示对话窗
下面给出几种形式
tk.messagebox.showinfo(title=\'\',message=\'\')#提示信息对话窗 tk.messagebox.showwarning()#提出警告对话窗 tk.messagebox.showerror()#提出错误对话窗 tk.messagebox.askquestion()#询问选择对话窗
如果给出如下定义就是打印出我们所选项对应的值
def hit_me(): print(tk.messagebox.askquestion(title=\'Hi\', message=\'hahahaha\'))
同样创建方法都是一样的形式
print(tk.messagebox.askquestion())#返回yes和no print(tk.messagebox.askokcancel())#返回true和false print(tk.messagebox.askyesno())#返回true和false print(tk.messagebox.askretrycancel())#返回true和false
完整代码:
import tkinter as tk import tkinter.messagebox window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') def hit_me(): #tk.messagebox.showinfo(title=\'\',message=\'\')#提示信息对话窗 #tk.messagebox.showwarning()#提出警告对话窗 #tk.messagebox.showerror()#提出错误对话窗 #tk.messagebox.askquestion(title=\'Hi\', message=\'hahahaha\')#询问选择对话窗 print(tk.messagebox.askquestion(title=\'Hi\', message=\'hahahaha\'))#打印出我们所选项对应的值 tk.Button(window,text=\'Hit me\',command=hit_me).pack() ##显示出来 window.mainloop()
演示:
pack grid place 放置位置
pack
首先我们先看看我们常用的pack()
, 他会按照上下左右的方式排列.
tk.Label(window, text=\'1\').pack(side=\'top\')#上 tk.Label(window, text=\'1\').pack(side=\'bottom\')#下 tk.Label(window, text=\'1\').pack(side=\'left\')#左 tk.Label(window, text=\'1\').pack(side=\'right\')#右
grid
接下里我们在看看grid()
, grid 是方格, 所以所有的内容会被放在这些规律的方格中.
for i in range(4): for j in range(3): tk.Label(window, text=1).grid(row=i, column=j, padx=10, pady=10)
以上的代码就是创建一个四行三列的表格,其实grid
就是用表格的形式定位的。这里的参数 row
为行,colum
为列,padx
就是单元格左右间距,pady
就是单元格上下间距。
place
再接下来就是place()
, 这个比较容易理解,就是给精确的坐标来定位,如此处给的(20,10)
,就是将这个部件放在坐标为(x,y)
的这个位置 后面的参数anchor=nw
就是前面所讲的锚定点是西北角。
tk.Label(window, text=1).place(x=20, y=10, anchor=\'nw\')
完整代码(只能用一种方式放置):
import tkinter as tk window = tk.Tk() window.title(\'my window\') ##窗口尺寸 window.geometry(\'200x200\') #pack tk.Label(window, text=\'1\').pack(side=\'top\')#上 tk.Label(window, text=\'1\').pack(side=\'bottom\')#下 tk.Label(window, text=\'1\').pack(side=\'left\')#左 tk.Label(window, text=\'1\').pack(side=\'right\')#右 #gird for i in range(4): for j in range(3): tk.Label(window, text=1).grid(row=i, column=j, padx=10, pady=10) #place tk.Label(window, text=1).place(x=20, y=10, anchor=\'nw\') ##显示出来 window.mainloop()
例子 登录窗口1
这一次效果图是这样的:
都是前面熟悉的参数。为了防止大家忘记,特意加上代码注释。
界面创建
# welcome image canvas = tk.Canvas(window, height=200, width=500)#创建画布 image_file = tk.PhotoImage(file=\'welcome.gif\')#加载图片文件 image = canvas.create_image(0,0, anchor=\'nw\', image=image_file)#将图片置于画布上 canvas.pack(side=\'top\')#放置画布(为上端)
这里创建的就是我们效果图中的welcome
, 如果你想使用和我一样的 welcome 的图片, 你可以在这里下载。
# user information tk.Label(window, text=\'User name: \').place(x=50, y= 150)#创建一个`label`名为`User name: `置于坐标(50,150) tk.Label(window, text=\'Password: \').place(x=50, y= 190) var_usr_name = tk.StringVar()#定义变量 var_usr_name.set(\'example@python.com\')#变量赋值\'example@python.com\' entry_usr_name = tk.Entry(window, textvariable=var_usr_name)#创建一个`entry`,显示为变量`var_usr_name`即图中的`example@python.com` entry_usr_name.place(x=160, y=150) var_usr_pwd = tk.StringVar() entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, show=\'*\')#`show`这个参数将输入的密码变为`***`的形式 entry_usr_pwd.place(x=160, y=190)
这里就是创建我们熟悉的登录界面,就是常见的用户名,密码。
# login and sign up button btn_login = tk.Button(window, text=\'Login\', command=usr_login)#定义一个`button`按钮,名为`Login`,触发命令为`usr_login` btn_login.place(x=170, y=230) btn_sign_up = tk.Button(window, text=\'Sign up\', command=usr_sign_up) btn_sign_up.place(x=270, y=230)
这里定义的就是我们的登录按钮。
触发功能
def usr_login(): pass def usr_sign_up(): pass
本节我们只是把登录的界面做出来,并没有对触发功能详细的去定义。等下节会继续完善这个例子。
例子 登录窗口2
这一次效果图是这样的:
触发的 usr_login 功能
##这两行代码就是获取用户输入的`usr_name`和`usr_pwd` usr_name = var_usr_name.get() usr_pwd = var_usr_pwd.get() ##这里设置异常捕获,当我们第一次访问用户信息文件时是不存在的,所以这里设置异常捕获。 ##中间的两行就是我们的匹配,即程序将输入的信息和文件中的信息匹配。 try: with open(\'usrs_info.pickle\', \'rb\') as usr_file: usrs_info = pickle.load(usr_file) except FileNotFoundError: ##这里就是我们在没有读取到`usr_file`的时候,程序会创建一个`usr_file`这个文件,并将管理员 ##的用户和密码写入,即用户名为`admin`密码为`admin`。 with open(\'usrs_info.pickle\', \'wb\') as usr_file: usrs_info = {\'admin\': \'admin\'} pickle.dump(usrs_info, usr_file)
这一部分就是将用户输入的用户名和密码获取到,和我们保存在usr_file
中的数据对比。针对正确的密码和错误的密码分别对待.
#如果用户名和密码与文件中的匹配成功,则会登录成功,并跳出弹窗`how are you?`加上你的用户名。 if usr_name in usrs_info: if usr_pwd == usrs_info[usr_name]: tk.messagebox.showinfo(title=\'Welcome\', message=\'How are you? \' + usr_name) ##如果用户名匹配成功,而密码输入错误,则会弹出\'Error, your password is wrong, try again.\' else: tk.messagebox.showerror(message=\'Error, your password is wrong, try again.\') else: # 如果发现用户名不存在 is_sign_up = tk.messagebox.askyesno(\'Welcome\', \'You have not sign up yet. Sign up today?\') # 提示需不需要注册新用户 if is_sign_up: usr_sign_up()
下面是用户名存在但是一个密码正确, 一个密码错误.
下面是用户不存在, 提示需不需要注册一个新的用户.
因为本节只是定义usr_sign_up
并没有实质功能,所以选择之后没有太大变化。 这一部分就是匹配的主要内容,如果匹配成功,就会登录进去,否则就会失败。
本节主要是详细介绍登录功能,下节会继续完善注册命令。
例子 登录窗口3
这一次效果图是这样的:
usr_sign_up 界面
window_sign_up = tk.Toplevel(window) window_sign_up.geometry(\'350x200\') window_sign_up.title(\'Sign up window\')
这一段首先是创建一个注册的窗口。这里和以往不同的是,多了一个tk.Toplevel
我们打个比方,就好像我们前面所学 的frame
一样,就是在编辑的功能下还有很多功能一样,这里就是在主体窗口的window
上创建一个Sign up window
窗口。
new_name = tk.StringVar()#将输入的注册名赋值给变量 new_name.set(\'example@python.com\')#将最初显示定为\'example@python.com\' tk.Label(window_sign_up, text=\'User name: \').place(x=10, y= 10)#将`User name:`放置在坐标(10,10)。 entry_new_name = tk.Entry(window_sign_up, textvariable=new_name)#创建一个注册名的`entry`,变量为`new_name` entry_new_name.place(x=150, y=10)#`entry`放置在坐标(150,10). new_pwd = tk.StringVar() tk.Label(window_sign_up, text=\'Password: \').place(x=10, y=50) entry_usr_pwd = tk.Entry(window_sign_up, textvariable=new_pwd, show=\'*\') entry_usr_pwd.place(x=150, y=50) new_pwd_confirm = tk.StringVar() tk.Label(window_sign_up, text=\'Confirm password: \').place(x=10, y= 90) entry_usr_pwd_confirm = tk.Entry(window_sign_up, textvariable=new_pwd_confirm, show=\'*\') entry_usr_pwd_confirm.place(x=150, y=90) # 下面的 sign_to_Mofan_Python 我们再后面接着说 btn_comfirm_sign_up = tk.Button(window_sign_up, text=\'Sign up\', command=sign_to_Mofan_Python) btn_comfirm_sign_up.place(x=150, y=130)
相信大家对这一段代码已经很熟悉了,因为这是大家前面所学过的知识。其实就是像我们平时所见的注册窗口有一样,在Sign up window
窗口 上添加new_name
, new_pwd
, new_pwd_confirm
,还有最后一个注册按钮。这里便于大家复习,我们将new_name
这段详细介绍一下(如代码注释)。 到这里就完成了我们这个注册的主要界面用户名,密码,确认密码。效果图如下:
sign_to_Mofan_Python() 功能
def usr_sign_up(): def sign_to_Mofan_Python(): ##以下三行就是获取我们注册时所输入的信息 np = new_pwd.get() npf = new_pwd_confirm.get() nn = new_name.get() ##这里是打开我们记录数据的文件,将注册信息读出 with open(\'usrs_info.pickle\', \'rb\') as usr_file: exist_usr_info = pickle.load(usr_file) ##这里就是判断,如果两次密码输入不一致,则提示`\'Error\', \'Password and confirm password must be the same!\'` if np != npf: tk.messagebox.showerror(\'Error\', \'Password and confirm password must be the same!\') ##如果用户名已经在我们的数据文件中,则提示`\'Error\', \'The user has already signed up!\'` elif nn in exist_usr_info: tk.messagebox.showerror(\'Error\', \'The user has already signed up!\') ##最后如果输入无以上错误,则将注册输入的信息记录到文件当中,并提示注册成功`\'Welcome\', \'You have successfully signed up!\'` ##然后销毁窗口。 else: exist_usr_info[nn] = np with open(\'usrs_info.pickle\', \'wb\') as usr_file: pickle.dump(exist_usr_info, usr_file) tk.messagebox.showinfo(\'Welcome\', \'You have successfully signed up!\') ##然后销毁窗口。 window_sign_up.destroy()
这里其实和前面所讲的login
功能类似,如代码注释。
注册成功就是我们一开始展示的效果图。
到此,我们的这个程序已经完善。这里给大家奉上我们最后的成果。
完整代码:
import tkinter as tk import pickle import tkinter.messagebox window = tk.Tk() window.title(\'Welcome To Myapp!\') ##窗口尺寸 window.geometry(\'450x300\') # welcome image canvas = tk.Canvas(window, height=200, width=500)#创建画布 image_file = tk.PhotoImage(file=\'welcome.gif\')#加载图片文件 image = canvas.create_image(0,0, anchor=\'nw\', image=image_file)#将图片置于画布上 canvas.pack(side=\'top\')#放置画布(为上端) # user information tk.Label(window, text=\'用户名: \').place(x=50, y= 150)#创建一个`label`名为`User name: `置于坐标(50,150) tk.Label(window, text=\'密码: \').place(x=50, y= 190) #用户名输入框 var_usr_name = tk.StringVar()#定义变量 var_usr_name.set(\'example@python.com\')#变量赋值\'example@python.com\' entry_usr_name = tk.Entry(window, textvariable=var_usr_name)#创建一个`entry`,显示为变量`var_usr_name`即图中的`example@python.com` entry_usr_name.place(x=160, y=150) #密码输入框 var_usr_pwd = tk.StringVar() entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, show=\'*\')#`show`这个参数将输入的密码变为`***`的形式 entry_usr_pwd.place(x=160, y=190) #登录事件 def usr_login(): ##这两行代码就是获取用户输入的`usr_name`和`usr_pwd` usr_name = var_usr_name.get() usr_pwd = var_usr_pwd.get() ##这里设置异常捕获,当我们第一次访问用户信息文件时是不存在的,所以这里设置异常捕获。 ##中间的两行就是我们的匹配,即程序将输入的信息和文件中的信息匹配。 try: with open(\'usrs_info.pickle\', \'rb\') as usr_file: usrs_info = pickle.load(usr_file) except EOFError: ##这里就是我们在没有读取到`usr_file`的时候,程序会创建一个`usr_file`这个文件,并将管理员 ##的用户和密码写入,即用户名为`admin`密码为`admin`。 with open(\'usrs_info.pickle\', \'wb\') as usr_file: usrs_info = {\'admin\': \'admin\'} pickle.dump(usrs_info, usr_file) #如果用户名和密码与文件中的匹配成功,则会登录成功,并跳出弹窗`how are you?`加上你的用户名。 if usr_name in usrs_info: if usr_pwd == usrs_info[usr_name]: tk.messagebox.showinfo(title=\'欢迎\', message=\'你好\' + usr_name) ##如果用户名匹配成功,而密码输入错误,则会弹出\'Error, your password is wrong, try again.\' else: tk.messagebox.showerror(message=\'错误,你的密码有问题,请重新输入\') else: # 如果发现用户名不存在 is_sign_up = tk.messagebox.askyesno(\'Welcome\', \'你还没有注册,现在注册?\') # 提示需不需要注册新用户 if is_sign_up: usr_sign_up() #注册事件 def usr_sign_up(): def sign_to_app(): ##以下三行就是获取我们注册时所输入的信息 np = new_pwd.get() npf = new_pwd_confirm.get() nn = new_name.get() ##这里是打开我们记录数据的文件,将注册信息读出 with open(\'usrs_info.pickle\', \'rb\') as usr_file: exist_usr_info = pickle.load(usr_file) ##这里就是判断,如果两次密码输入不一致,则提示`\'Error\', \'Password and confirm password must be the same!\'` if np != npf: tk.messagebox.showerror(\'Error\', \'两次密码输入不一致哦!\') ##如果用户名已经在我们的数据文件中,则提示`\'Error\', \'The user has already signed up!\'` elif nn in exist_usr_info: tk.messagebox.showerror(\'Error\', \'这个用户名已经注册了!\') ##最后如果输入无以上错误,则将注册输入的信息记录到文件当中,并提示注册成功`\'Welcome\', \'You have successfully signed up!\'` ##然后销毁窗口。 else: exist_usr_info[nn] = np with open(\'usrs_info.pickle\', \'wb\') as usr_file: pickle.dump(exist_usr_info, usr_file) tk.messagebox.showinfo(\'Welcome\', \'你成功注册了!\') ##然后销毁窗口。 window_sign_up.destroy() window_sign_up = tk.Toplevel(window) window_sign_up.geometry(\'350x200\') window_sign_up.title(\'用户注册\') #新用户名 new_name = tk.StringVar()#将输入的注册名赋值给变量 new_name.set(\'example@python.com\')#将最初显示定为\'example@python.com\' tk.Label(window_sign_up, text=\'用户名: \').place(x=10, y= 10)#将`User name:`放置在坐标(10,10)。 entry_new_name = tk.Entry(window_sign_up, textvariable=new_name)#创建一个注册名的`entry`,变量为`new_name` entry_new_name.place(x=150, y=10)#`entry`放置在坐标(150,10). #新密码 new_pwd = tk.StringVar() tk.Label(window_sign_up, text=\'密码: \').place(x=10, y=50) entry_usr_pwd = tk.Entry(window_sign_up, textvariable=new_pwd, show=\'*\') entry_usr_pwd.place(x=150, y=50) #防止密码填错 new_pwd_confirm = tk.StringVar() tk.Label(window_sign_up, text=\'重复密码: \').place(x=10, y= 90) entry_usr_pwd_confirm = tk.Entry(window_sign_up, textvariable=new_pwd_confirm, show=\'*\') entry_usr_pwd_confirm.place(x=150, y=90) # 下面的 sign_to_app btn_comfirm_sign_up = tk.Button(window_sign_up, text=\'注册\', command=sign_to_app) btn_comfirm_sign_up.place(x=150, y=130) # 登录和注册按钮 btn_login = tk.Button(window, text=\'登录\', command=usr_login)#定义一个`button`按钮,名为`Login`,触发命令为`usr_login` btn_login.place(x=170, y=230) btn_sign_up = tk.Button(window, text=\'注册\', command=usr_sign_up) btn_sign_up.place(x=270, y=230) ##显示出来 window.mainloop()
演示: