欢迎光临散文网 会员登陆 & 注册

【莫烦Python】Tkinter 做简单的窗口视窗 Python GUI

2022-06-10 21:56 作者:无双小骏  | 我要投稿

tkinter是一个GUI图像窗口,例如说我们打开windows或者mac后都会有一个窗口,这个就是GUI界面。例如说我们想要开发一个计算器就需要运用GUI界面,要开发一个用户可以体验的窗口,例如按钮1按钮2,我们要做的就是窗口的背后添加可视的效果。

首先我们要导入tkinter库(import tkinter as tk):把tkinter用一个缩写tk代替。

第一步建立一个窗口,把窗口的名字这里设为window(window = tk.Tk())

第二步要给窗口弄个名字,也就是title(window.title('my window')).

第三部要给窗口设立大小,也就是长宽。(window.geometry('200x100'))

第四部我们要设立一个label,也就是图中窗口中的绿色的部分,有点类似计算器显示数字的屏幕的部分,起到一个显示的作用,这里在视频中首先要为label起一个名字,视频中命名为l,然后括号里首先第一个参数是要在哪个窗口里设立这个label,然后可以设置文本、宽高,还有字体和背景颜色。

第五部分我们要设立一个pack,pack的作用是迷人将L的位置设在中上部分,而pack前的值是window的案件,这里是label,后续也可以是button等。

最后要给window加一个mainloop,使这个窗口不断地刷新(while循环),基本上所有的窗口文件都会有一个mainloop。

其余代码如下:

import tkinter as tk

window = tk.Tk()
window.title("my window")
window.geometry('200x100')
var = tk.StringVar()
l=tk.Label(window,textvariable=var,bg='green',font=('Arial',12),width=15,height=2)          #width与height的大小决定着label的大小,而决定width和height的大小的因素是字符arial的大小
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='hit me',width=15,height=2,command=hit_me)

b .pack()                    #pack的用处是默认将L的位置设在中上部分
window.mainloop()    #使这个窗口不断地刷新——while循环,基本上所有的窗口文件都会有一个mainloop
#StringVar是Tk库内部定义的字符串变量类型,在这里用于管理部件上面的字符;

#这个可以跟踪变量值的变化,普通的python变量不能即时地显示在屏幕上面。

#StringVar并不是python内建的对象, 而是属于Tkinter下的对象。

#在使用界面编程的时候, 有些时候是需要跟踪变量的值的变化,以保证值的变更随时可以显示在界面上。由于python无法做到这一点,所以使用了tcl的相应的对象,也就是StringVar、BooleanVar、DoubleVar、IntVar所需要起到的作用

因为我们要实现的内容是一个窗口内有两个组件,一个是显示的组件label,另一个组件是按钮button,当我们点击按钮之后,显示的是you hit me,而当我们再次点击button之后,you hit me消失。所以我们的label就不再是一个定量,也就不再只是一个text输出去you hit me这么简单了,因为它会变成无值,是一个变量,因此就要用到StringVar。将其套入到label当中。

#StringVar并不是python内建的对象, 而是属于Tkinter下的对象。

#在使用界面编程的时候, 有些时候是需要跟踪变量的值的变化,以保证值的变更随时可以显示在界面上。由于python无法做到这一点,所以使用了tcl的相应的对象,也就是StringVar、BooleanVar、DoubleVar、IntVar所需要起到的作用

然后我们要定义一个hit_me,这个hit_me命名为任意值均可,至于global,我认为它是一个储存被定义的hit_me值得仓库,然后我们用if...else进行一个循环。这里要注意hit_me和on_hit的区别,hit_me一是按钮button的显示的内容text,二是定义的函数在button中被command来链接,而on_hit是一个值,要么为Fales要么为True,这里在循环前将on_hit的值设为Fales,然后再hit_me函数所嵌套的循环当中,如果on_hit的值为Falese,那么执行两个操作,先是将on_hit的值由假变为真,同时输出you hit me 的字样,那么在判断结束后真值存入global(前面说过它理解为是一个仓库),当我们再次点击的时候是第二次判断,此时将第一次循环后由假变真的值从global中调用出来判断,因为此时是真值从而执行else,首先将真变为假,同时输出的内容为空。

定义完函数后简单地创建一个button,显示在window窗口当中,默认文本为hit me,再设立宽高和内置的链接函数command。这里主义我们的pack前面要新建一个,命名为b,因为button设立的名字也是b,执行即可成功,这也就是第一个简单而又充满难度的window窗口的结束。





上一次讲到了label和button,这次我们要讲的一个是用来输入用户名或密码这个输入框的作用的东西entry,然后我们还需要用到两个button,最下面还有一个text,一个按钮用来将上面的内容复制到指针上,下面的那妞用来将上面的内容复制到最后面。

我们例如说在登陆qq时的输入框密码中,输入的字符都是*,这里就用到了entry里的show(show=‘*’)

import tkinter as tk

window = tk.Tk()
window.title("my window")
window.geometry('200x280')
e = tk.Entry(window,show='*')
e.pack()

def insert_point():
    var = e.get()
    t.insert('insert',var)
def insert_end():
    var=e.get()
    t.insert('end',var)

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()
t=tk.Text(window,height=2)
t.pack()

首先明确一点的是我们创立了两个button,因此就需要定义两个函数,这两个函数所实现的目的一个是用来将输入的内容在鼠标所处的位置下输出,另一个按钮是用来在文本末尾输出,我们将前者命名为insert_point,后者命名为insert_end,并且两个按钮默认显示的内容(text)也是二者。其次我们要设立一个显示我们输入的内容的组件entry,这个entry是要在window下显示的(因为目前我们创建的窗口命名为window),所以window也就是entry第一个参数,意思是把这个entry组件放置到名称为window的窗口下,show前面提过是显示的意思,视频末尾作者还讲过可以把*设为1,那样子用户所输入的一切内容显示出来的就只会是1(但实际内容时不变的),让用户误认为电脑中了病毒。接下来的两个函数,二者的区别只是说把entry中的内容追加到text当中的位置不一样而已,内容是一样的,所以都有同一行代码(var = e.get()),就是说设立一个常量名为var,它的内容是使用get将e(entry)的所有内容获取初来,之所以是e而不是entry,是因为我们把entry的内容组合成了一个量为e,这个e就代表这个entry,赋值的意思,好比说a=15,所以输入a的话就会显示出15一样。t.insert里面有连个值,一个是insert/end,另一个是var,这行代码的意思是:insert是插入,end是末尾,由于没有指定位置所以默认直接插入到鼠标所指的位置,指定了末尾的话就是在最后面插入,而同时视频中也讲了我们可以不用insert直接指定行列,例如视频中的2.2意思就是插入到第二行的第二列(这里要注意的是python中的列是从零开始的)。



这次要学习的组件叫做:List。而今天要做的就是在上面有一个黄色的label,然后我们选中下面的众多数字当中的一个,然后单击名为print selection的组件就会在黄色部分所显示。

首先我们要知道完成这个项目需要用到哪些东西,名为print selection的按钮button不必多说,而上面的黄色区域和下面一大堆的数字区域则分别需要用到的是前面我们所学的lebel,和这次我们要学习用到的listbox。listbox名如其名,list是列表,box是箱子,合起来就是一个用来存储数据的盒子按以列的方式显示出来。之前我们说过在python中是不支持跟踪变量的值发生变化的,因此我们还是分别需要给这两个组件都加上StringVar,这里给黄色区域命名为var1,而下面的区域设置为var2。

import tkinter as tk
window = tk.Tk()
window.title("my window")
window.geometry('200x280')
var1 = tk.StringVar()
l = tk.Label(window,bg='yellow',width=4,textvariable=var1)
l.pack()

def print_selection():          #为了光标选择这一项,就会到label标签当中,因此要设立一个这样的函数。
    value = lb.get(lb.curselection())       #curse是光标,selection是选择,,get是得到,让value得到光标选择的值。
    var1.set(value)                         #set是放置,将光标选择的值value放置到var1(黄色区域)内

b1=tk.Button(window,text='print selection',width=15,height=2,command=print_selection)
b1.pack()
var2 = tk.StringVar()
var2.set((11,22,33,44))    #set在英文中是放置的意思,也就是说在var2里放置四个名为11,22,33,44的数字,而我们要放的数字是以元组的方式放入的。
lb=tk.Listbox(window,listvariable=var2)
list_items = [1,2,3,4]          #创建一个列表,内容是1,2,3和4。
for item in list_items:         #将列表的内容逐个插入到lb的末端。也可以用到上节课学到的index索引插入。
    lb.insert('end',item)
lb.insert('end',item)
lb.insert(1,'first')
lb.insert(2,'second')
lb.delete(2)
lb.pack()
window.mainloop()

图片中的第一个数据之所以是11,是因为原本的数据从上到家时11,22,33,44,1,2,3,4。后来手动插入了一个名为first的数据放到了1的位置,而前面讲过python的第一位是0,所以名为first的数据插入到了11的下面,而second原本是要在first的下面的,并非是现在的22,之所以没有是因为作者用delete把它给删除了。总而言之:作者先是通过set将装有11,22,33,44数据的元组放入到了var2,后来又通过循环的方式放入了1,2,3,4,最后又手动插入了first和second连个数据,然后删除了second。



Radiobutton选择按钮,类似于一个调查问卷,问你是男还是女,如果你选择了男,那么显示你该去男厕所上厕所,如果你是个女的,那就显示你应该去女厕所上厕所。而视频中作者的内容是需要三个radiobutton,名字分别为OptionABC。同时还需要设立一个label来显示我们点击按钮后所呈现出的内容。

import tkinter as tk
window = tk.Tk()
window.title("my window")
window.geometry('200x200')
var = tk.StringVar()
l = tk.Label(window,bg='yellow',width=24,text='empty')
l.pack()
def print_selection():
    l.config(text='you have selected'+var.get())
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()

Radiobutton的选项首先要指定其设置在哪个窗口中,并且显示的字是怎样的,然后它代表了给variable的这个var赋值成怎样的字符,可以这样来理解,Radiobutton这个组件自带了一个字符存储器叫variable,它是用来存储数据的,而数据在这里叫做value,所以我们做的操作时将这个字符存储器与前面我们所创建的var所挂钩,并且字符存储器里面所存储的字符,也就是value我们给他取名为ABC,最后我们要定义一个函数,来起到点击这个按钮的话,就会执行这个函数,这个函数是用来改变Label的,原本的text是empry,后来点击按钮之后就会改变成我们的固定字符'you have selected'加上我们给var所传递的内容即可。由于显示的内容较长,因此我们需要设置至少能过让完整字符输出出来的而长度给label。



这次要讲的部件名为scale部件,它类似于我们要拉动的一个条,与之不同的是scale会返回一个具体的数字,在我们拉动它的时候上面的值会改变,其实就像是测拉力的器械一样,如果我们用力拉伸,器械上的显示屏所显示你的力气就会越大。

i首先我们肯定是需要一个负责显示数值变化的label,当然还有我们这次要讲的scale,scale内的值与大部分组件一样,首当其冲的就是我们要把这个scale设置在哪个窗口,这里当然是window了。而在scale上面有一个留白的部分,这个部分就是label,我们可以对其进行设置让其显示出一些文字,就好比我们吃汉堡,中间的是精华而上下是面包,上面的面包是用来显示名字或者标题的,下面的面包片是用来显示刻度的,就像本次的1.00和6.00之类的,类似于尺子的刻度。每一个尺子都有其特定的长度,大多数为20cm,而我们的sacle可以自定义其长度,这里我们设置为从5到10,并且可以控制其为横向还是纵向的,从作者的代码中我们可以得知横向的参数是HORIZONTAL。接下来我们该设置其长度了,注意这里我们的长度不再是字符的长度了,而是像素的长度,也就是和窗口的大小一样的单位。showvalue就是我们显示的值,在这里我们可以设置为0,也就是FALSE不显示,同理如果是1的话就是显示,显示的值得位置就是在我们拖动的指针的上面进行显示,之所以这次不进行显示是因为在上面的黄色区域已经显示了,就没有必要多此一举了。那么接下来我们还可以设置标签的单位长度,参数是tickterval,同时还可以设置它的保留几位小数,不保留小数(整数)就是1,保留一位小数就是0.1,不保留小数就是0.01,同时为了让scale的值能够在黄色区域所显示我们还需要设置一个command并设置其参数。

mport tkinter as tk
window = tk.Tk()
window.title("my window")
window.geometry('150x200')
l = tk.Label(window,bg='yellow',width=20,text='empty')
l.pack()
def print_selection(v):
    l.config(text='you have selected'+v)

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,Checkbutton和Radiobutton虽然都是按钮但略显不同,如果说Checkbutton是多选项,那么Radiobutton是单选项。例如说如下图我们可以既喜欢python又喜欢c++(不专一)。

import tkinter as tk
window = tk.Tk()
window.title("my window")
window.geometry('150x200')
l = tk.Label(window,bg='yellow',width=20,text='empty')
l.pack()
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')
var1=tk.IntVar()
var2=tk.IntVar()
c1 = tk.Checkbutton(window,text='Python',variable=var1,onvalue=1,offvalue=0,command=print_selection)
c2 = tk.Checkbutton(window,text='C++',variable=var2,onvalue=1,offvalue=0,command=print_selection)
c1.pack()
c2.pack()
window.mainloop()

&是and的意思,而config是打印的意思,作者的作品中有连个选项(python和c++),因此我们要设立两个checkbutton,而为了实现点击每一个button的时候和点击两个button时和都不点击button和都点击时的效果不一样,我们同样需要定义一个函数,这个函数来实现我们点击不同的按钮所触发的不同的效果,而点击的按钮的参数和radiobutton的内容大致一样,也是先输入所要存在的窗口,然后输入显示的文本,同时分别绑定var1和var2,这个variable的值由于onvalue和offvalue的存在要么是1要么是2,至于是1还是2取决于是否点击,点击的话就触发onvalue的效果让variable的值为赋给var1,var1进入被定义的函数中判断,若为1则......最后用command和函数挂钩。



今天我们要学习的是在tkinter中放置画布,并且可以调换其位置和形状,要想创建画布,我们既要用到Canvas命令,先设置其要放置在哪个窗口,这里是window窗口,bg是北京颜色,这里是蓝色,高宽分别设置成100和200,因为我们的窗口window就是200*200,因此下面留白了100的部分用来房button,button只需要设置其函数即可,内容显示为move。而关键是在canvas中加入图片,要想加入图片,在canvas创建好的基础上创建PhotoImage,然后其参数用file来挂钩我们想要插入的图片的名字(在mac里只支持gif格式,实测在window中也是如此,但是或许不同的版本应该可以),然后加载的canvas是要创建图像,首先我们要设立一个画布中的点,而anchor是设立锚定的点。具体参数如下图:

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='hope.gif')
image=canvas.create_image(10,0,anchor='nw',image=image_file)#在canvas当中因为是nw,所以以左上角为原点,而10,10就代表向下10想右10
x0,y0,x1,y1 = 50,50,80,80
line = canvas.create_line(x0,y0,x1,y1)                                  #线段有起点和终点,而我们设置线段的长度要有四个数据,前两个是起点的x与y,后两个是终点的x与y。
oval = canvas.create_oval(x0,y0,x1,y1,fill='red')                       #fill是设置填充的颜色
arc=canvas.create_arc(x0+30,y0+30,x1+30,y1+30,start=0,extent=180)       #entent是翻转的角度,start是扇形开始时的边的位置。
rect=canvas.create_rectangle(100,30,100+20,30+20)                       #矩形的特点就是对边相等,因此我们也是只需要设立起点(100,30)和终点(120,50)即可。
def moveit():               #定义一个名为moveit的函数
    canvas.move(rect,0,2)       #0表示x,2表示y,也就是说横向不变,纵向下降2的单位长度,move是移动的意思
canvas.pack()
b=tk.Button(window,text='move',command=moveit).pack()
window.mainloop()

这里有一个比较有意思的现象,作者在没有定义moveit的时候是能将结果输出的,但是我没定义的时候会报错,因此在跟着做的时候一定要先理解,看完视频后再运行测试。



这此要学习的内容那个叫做Menubar,而在mac系统中的menubar在最上面,我们这次并不会执着于实现具体的功能,而是让其余label能够附和在一起即可。首先我们要定义menubar,menubar不需要任何东西,只需要定义说我们的窗口有一个menubar即可,后面我们单独来设置。并且每一个menubar都要设置其函数内核。同时显示的黄色区域是用label来显示的。

我们要实现的内容是窗口左上角有名为File的选项,点开该选项会出现New、Open、Save,点击New或Open或Save,三个按钮任意点击一个的话就会从do 0加一...。这三个按钮除了显示的text不同之外都一样,所以command所挂钩的函数都是相同的。我们可以看到作者的Exit上面有一个分割线,这个分割线就用:filemenu.add_separate()就好。而作者的Edit中下面的两个按钮呢是mac自带的功能并非是设计的所以不用去管,只要设置Cut、Copy和Paste即可。我们可以直接copy上面已经打好的内容,然后改一下名字和label显示的名字即可,而command在此演示中就不做不同的修改了,只要知道每一个功能都会执行command所链接的函数的功能即可,相当于一个框架,具体实施的内容还是需要具体的去实现。最后我们在这个File里还加了一个Import,import下面还有一个子选项,创建形式和前面两个差别不大,只不过这次因为我们的import是在file下,而file在filemenu下,因此import要与filemenu挂钩。

import tkinter as tk
window = tk.Tk()
window.title("my window")
window.geometry('200x200')
l = tk.Label(window,text='',bg='yellow')
l.pack()
counter = 0
def do_job():
    global counter
    l.config(text='do'+str(counter))        #改变我们label的一个参数
    counter+=1
menubar = tk.Menu(window)       #给window窗口设立一个Menu
filemenu = tk.Menu(menubar,tearoff=0)   #tearoff是设置能否分开,0是不能,1是能。这里作者改成0或1没有发现有什么明显的区别
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_command(label='Save',command=do_job)
filemenu.add_separator()
filemenu.add_command(label='Exit',command=window.quit)      #退出这个窗口

editmenu = tk.Menu(menubar,tearoff=0)   #tearoff是设置能否分开,0是不能,1是能。这里作者改成0或1没有发现有什么明显的区别
menubar.add_cascade(label='Edit',menu=editmenu)
editmenu.add_command(label='Cut',command=do_job)
editmenu.add_command(label='Copy',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='Submenu1',command=do_job)
window.config(menu=menubar)     #改变window的一个参数,把它的menu改变成我们定义好的menubar
window.mainloop()

后面我们要想实现这个内容首先要明确一点的是,filemenu和file的关系,这个代码我们创建了两个menu(filemenu和editmenu),而file是filemenu下拉框下的file下的一个副选框,虽然这个复选框所在的file是在filemenu下,但是它依旧要新建立一个下拉框,也就是说如果filemenu是老子的话,file是孩子,那么新建立的这个下拉框import虽然是孙子,但他和file不同,file是老子的一个选项,而import是又一个新建立的下拉框,所以从辈儿上将可能不是很大,但是其内核是与filemenu平等偏下的,之所以说是平等偏下,是因为它在filemenu下建立的,而与filemenu平等的是editmenu,他俩的老大都是menu,只能说filemenu多了个小弟,这个小弟又收了一个小弟,因此我们要这个小弟所收的小弟建立一个新的内核命名为submenu,这个新的内核命名为Import,这个被收的小弟也收了一个小弟,它自立门户当了个老大,收了一个叫Submenu1的小弟,而file一直是小弟,没有自立门户。



这一次我们要学习的是Frame框架,Frame小部件我们是在窗口中看不到的,但是它可以总结归纳起来我们在Frame里的小部件。可以把它想成一个用来对其他组件分类的归纳箱,把像label或者是button这样的部件想象成垃圾,厨余垃圾分成一类,有害垃圾分成一类。如下图所示左边的两个label被一个Frame圈着,右边的label被另一个Frame圈着,因此我们需要先定义三哥label。注意这个Frame是由主次之分的,如果说左右两边的Frame是同级,那么它俩都有一个共同的父集。设置其左右我们使用side参数来设置的,同时这里要注意的是设置其左右不是在window上的左右,而是在Frame上的左右

import tkinter as tk
window = tk.Tk()
window.title("my window")
window.geometry('200x200')
tk.Label(window,text='on the window').pack()
frm=tk.Frame(window)
frm.pack()
frm_l = tk.Frame(frm,)
frm_r = tk.Frame(frm)
frm_l.pack(side='left')
frm_r.pack(side='right')
tk.Label(frm_l,text='on the frm_l1').pack()
tk.Label(frm_l,text='on the frm_l2').pack()
tk.Label(frm_r,text='on the frm_r1').pack()
window.mainloop()

复制粘贴是好,但是我们要注意的是一定要记得修改一下。总而言之使我们在一个打的frame的基础上建立一个左边的frame和右边的frame,这样可以让我们更详细地了解到我们frame的布局。



这一次我们要讲述如何来放置我们所创造的部件,一种是我们常见的部件pack,前面已经用过很多了,例如说我们设立了一个label,那么要想让label显示出来就需要设立一个label.pack(),而我们似乎不知道的是pack是可以设立其位置的,例如说我这样的代码。

import tkinter as tk
window = tk.Tk()
window.title("my window")
window.geometry('200x200')
tk.Label(window,text='on the window').pack(side='top')
tk.Label(window,text='on the window').pack(side='bottom')
tk.Label(window,text='on the window').pack(side='left')
tk.Label(window,text='on the window').pack(side='right')
window.mainloop()

接下来我们讲一下grid,grid如果想让它方便显示的话我们要用到循环,设置其行列,例如说我们想设置一个四行三列的东西,我们可以这样的代码。

import tkinter as tk
window = tk.Tk()
window.title("my window")
window.geometry('200x200')
for i in range(4):
    for j in range(3):       tk.Label(window,text='1').grid(row=i,column=j)
window.mainloop()


这里比较难理解的就是循环的作用,实际上小编在去掉循环之后发现只是输出了一个1,尽管设置了其row行尾4,column列为3还是只有一个1,所以为了方便理解,就理解为如果想要输出类似有规则对称的散点图,就要在行的循环下套一个列的循环进行使用。除了行列的代码我们还可以设置padx和pady,二者是内部关于x和y的扩展,每一个文本的占地面积就会增大,也可以设置其ipadx和ipady,这个是它内部设置的,注意所谓的扩展是指文本与文本之间关于x与y方向的扩展。而作者最常用的还是place,place就是从窗口的左上角为0点,x=10就是往右移10.y=100就是往下100的距离,同时也可以设置其方向在哪里,例如anchor=‘nr’也就是西北角,这个图我们之前学过。注意这里的100与我们熟知的xy坐标不同的是y是反着的。



这一次讲到的是tkinter的一个弹出的窗口,就例如我们点击一下确定然后就会报错,或者是点击删除之后就会弹出“你真的要删除这个文件嘛”之类的功能,

首先要想激活窗口我们就需要创立一个button,点击这个按钮之后才能有弹窗被弹出,因此这个button要连接一个函数,这个函数也自然就是弹窗的函数,函数名这个变量命名为hit_me,弹窗的组件叫messagebox,而作者代码中的showinfo就是弹出的窗口中的火箭的标志,注意不同的messagebox所弹出的图标是不一样的,我们用另外一个messagebox,把火箭替换成showwarning,意思就是展示错误的意思,又或者我们换成showerror,和warning相比,warning更多的是有错误但影响不大,而error则是会影响主程序的图标展示。还有一个不是以show开头了,而是以ask,askquestion的返回值是一个字符串的yes或者no。点击yes或者no,在python的Idle也自然会返回yes或者no。若把askquestion改成askyesno的话,所返回的no或者yes对应的就不再是它们本了,yes的返回是True,no的返回是False,而最后一个asktycancel和askokcance,他们的返回也同样是True和Falese,和上述的内容无异就不讲了。

import tkinter.messagebox
window = tkinter.Tk()
window.title("my window")
window.geometry('200x200')
def hit_me():
tkinter.messagebox.showinfo(title='Hi',message='hahahaha')
tkinter.messagebox.showwarning(title='Hi',message='nononono') tkinter.messagebox.showerror(title='Hi',message='No!never')             #return 'yes','no'
print(tkinter.messagebox.askys(title='Hi',message='hahahahha'))    
tkinter.Button(window,text='hit me',command=hit_me).pack()
window.mainloop()

这里一定要注意一点的就是要调用messagebox,不然就会报错出现AttributeError: module ‘tkinter‘ has no attribute ‘messagebox的错误,意思是Python使用对话框显示提示信息出现无messagebox属性。



这次我们要做一个小例子,也就是实践。本次实践要做的是一个登录的窗口,而除了登录的窗口按钮还有一个注册的窗口,这个窗口会弹出很多弹窗来跟用户进行一个交流。

首先在设立完基本的窗口(大小标题都设置好了)后,我们还需要引入一个welcome的图片,这里就不去搞了,主要把组件搞了就好,因为作者的图片所谓的主页未必是本网站。不过解释一下作者图片的意思,作者导入这个图片运用了PhotoImage,file与图片名挂钩,然后设置其图片的位置,这个图片的变量名我们设为image_file,所以接下来在我们学过的画布按钮canvas中用file函数与这个图片挂钩来设置这个图片的位置。然后密码和账号两个位置要用label来设置,通过从笔记上看上上节课学完的place的方式来设置组件的位置,并为两个label来设立text告诉用户你在哪里输密码哪里输入账号,然后用户的密码账号输入框是用entry来解决,这个是变量因此我们需要用到很早就学的StringVar,账号密码各需要一个共两个。同时可以用set函数设立一个默认值给到账号,这是因为有一些用户不记得自己的账号,因此需要这样设置,同时密码也可以,不过大多数平台都会给它变成*。

然后我们还要设置一个登录和设置面两个按钮,这两个按钮都是用place来定义位置信息,我们已经定义好了主窗口,登录和设置的窗口按钮也做好了,接下来就要做一下login的功能,再做sign的功能。login是登录的意思,登录的时候不能说随便输入一个数据就能登录。在我们创建完login之后,就要创建sign up的功能,打开sign up,就会弹出一个让我们注册账号和密码的窗口,此刻就需要个label和三个entry和一个窗口,还有一个按钮,因为弹出的注册页面和一个新的window。我们创建一个新的窗口命名为window_sign_up,而我们就需要运用toplevel。Toplevel控件为其他空间提供单独的容器,比如框架。对简单的单独视窗应用来说,初始化Tk时创建的根Toplevel可能是你所需要的唯一外框。

因为这个toplevel在window下,所以括号里就输入window。然后我们再调控好大小和标题就可以设置组件了。完整代码如下:

import tkinter.messagebox

window=tkinter.Tk()
window.title('Welcome to Mofan Python')
window.geometry('450x300')
var_usr_name=tkinter.StringVar()
var_usr_name.set('example@python.com')
entry_usr_name = tkinter.Entry(window,textvariable=var_usr_name)
entry_usr_name.place(x=160,y=150)
var_usr_pwd=tkinter.StringVar()
entry_usr_pwd=tkinter.Entry(window,textvariable=var_usr_pwd,show="*")
entry_usr_pwd.place(x=160,y=190)
def usr_login():
    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:
        with open('usrs_info.pickle','wb') as usr_file:
            usrs_info={'admin':'admin'}
            pickle.dump(usrs_info,usr_file)
    if usr_name in usrs_info:
        if usr_pwd ==usrs_info[usr_name]:
            tkinter.messagebox.showinfo('Welcome','How are you?'+usr_name)
        else:
            tkinter.messagebox.showerror(message='Error,your password is wrong,try again.')
    else:
        is_sign_up = tkinter.messagebox.askyesno("Welcome You have not sign up yet,Sign up today?")
        if is_sign_up:
            usr_sign_up()
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)
        if np!=npf:          #如果这个新的密码不等于库里已有的,那么就会跳出窗口让我们重复输入 
            tkinter.messagebox.showerror('Error',"Password and confirm password must be the same!")
        elif nn in exist_usr_info:     #如果已经存在信息在database,就是这个用户已经注册过了。
            tkinter.messagebox.showerror('Error','The user has already signed up!')
        else:
            exist_usr_info[nn] = np    #如果注册合格了就把这个信息加入这里。
            with open('usrs_info.pickle') as usr_file:
                pickle.dump(exist_usr_info,usr_file)
            tkinter.messagebox.showinfo('Welcome','You have successfully signed up!')
            window_sign_up.destroy()    
    window_sign_up=tkinter.Toplevel(window)
    window_sign_up.geometry('350x200')
    window_sign_up.title('Sign up window')
    new_name=tkinter.StringVar()
    new_name.set('example@python.com')
    tkinter.Label(window_sign_up,text='User name').place(x=10,y=10)
    entry_new_name=tkinter.Entry(window_sign_up,textvariable=new_name)
    entry_new_name.place(x=150,y=10)

    new_pwd= tkinter.StringVar()
    tkinter.Label(window_sign_up, text='Password').place(x=10, y=50)
    entry_new_pwd = tkinter.Entry(window_sign_up, textvariable=new_pwd,show='*')
    entry_new_pwd.place(x=150, y=50)

    new_pwd_confirm=tkinter.StringVar()
    tkinter.Label(window_sign_up,text='Confirm password:').place(x=10,y=90)
    entry_usr_pwd_confirm=tkinter.Entry(window_sign_up,textvariable=new_pwd_confirm,show='*')     #确认你的密码
    entry_usr_pwd_confirm.place(x=150,y=90)
 btn_comfirm_sign_up = tkinter.Button(window_sign_up,text='Sign up',command=sign_to_Mofan_Python)
    btn_comfirm_sign_up.place(x=150,y=130)


#login and sign up button
btn_login=tkinter.Button(window,text='Login',command=usr_login)
btn_login.place(x=170,y=230)
btn_sign_up = tkinter.Button(window,text='Sign up',command=usr_sign_up)
btn_sign_up.place(x=270,y=230)
window.mainloop()

























【莫烦Python】Tkinter 做简单的窗口视窗 Python GUI的评论 (共 条)

分享到微博请遵守国家法律