Python:GUI库tkinter(三)

这一章是对前两章的总结:

Python:GUI库tkinter(一)

Python:GUI库tkinter(二)

前两章是对控件的介绍,第一章可以知道各控件使用时的具体参数,第二章以具体的例子展示了每个控件的用法,本章将所有控件放在一起,看看构建一个GUI的一般方法与语句。

这可能是最好玩的python GUI入门实例! - 简书Python:GUI库tkinter(二)中的例子为例,给出制作一个具有注册登录功能的界面的一般流程:

复制代码
from tkinter import *
from tkinter import messagebox ①
import pickle

window=Tk()
window.title('My Window')  ②
window.geometry('500x300') #主窗口设置

#图片:Canvas      ③
canvas=Canvas(window,width=400,height=135,bg='green')
image_file=PhotoImage(file='Squirrel.png')  
canvas.create_image(200,0,anchor='n',image=image_file)
canvas.pack(side='top')

#文本:Label    ④
Label(window,text='Welcome',font=('Arial',16)).pack()
#输入框前的文本:用户和密码    
Label(window,text='Username',font=('Arial',14)).place(x=10,y=170)
Label(window,text='Password',font=('Arial',14)).place(x=10,y=210)

#输入框中的初始字:StringVar
var_username=StringVar()  ⑤
var_username.set('example@python.com')#设置初值

#输入框:Entry,通过构造时的参数textvariable显示之前的初始字 #用户名输入框    ⑥ entry_username=Entry(window,textvariable=var_username,font=('Arial',14))#这里的font是输入时显示的字体 entry_username.place(x=120,y=175) #密码输入框 entry_password=Entry(window,font=('Arial',14),show='*') entry_password.place(x=120,y=215) #用户登录功能函数    ⑦ def usr_login(): ... #用户注册功能函数 def usr_sign_up(): ... #登录与注册按钮,关联函数  ⑧ btn_login=Button(window,text='Login',command=usr_login) btn_login.place(x=120,y=240) btn_sign_up=Button(window,text='sign_up',command=usr_sign_up) btn_sign_up.place(x=200,y=240) #运行主框架    ⑨ window.mainloop()
复制代码

 各部分解释说明

from tkinter import *
from tkinter import messagebox 
import pickle

导入各种库,令笔者不解的是,虽然已经import *,但是如果要用到消息框,仍然需要再import messagebox,而不能直接用messagebox,具体原因未知。

pickle库则是,如果想将某些数据以序列化二进制数的形式保存到某个文本文件中(或从这些文件中提取序列化后的文本文件),就需要用到这个库,具体用法详见序列化 pickle JSON - ShineLe - 博客园

由于是登录界面模拟,所以自然要保存许多用户的信息,要用到EXCEL或者数据库,这时候也可以用pandas库进行写入或读取数据,具体用法见Python:pandas(一)——常用、读写函数read_csv、read_excel、to_csv - ShineLe - 博客园

window=Tk()
window.title('My Window')  ②
window.geometry('500x300') #主窗口设置

主框架(Tk类)构建最常用的三句话,所谓主框架就是最终显示的GUI所在的窗口。

这三句话的功能为:窗口实例化、窗口标题、窗口尺寸

 

#图片:Canvas      ③
canvas=Canvas(window,width=400,height=135,bg='green')
image_file=PhotoImage(file='Squirrel.png')  
canvas.create_image(200,0,anchor='n',image=image_file)
canvas.pack(side='top')

这一段话的目的是,加载一个图片到窗口内,需要用到Canvas控件,把图片显示到Canvas上,再把Canvas部署到主框架下。

canvas=Canvas(window,width=400,height=135,bg='green') 创建承接图片的Canvas控件:
image_file=PhotoImage(file='Squirrel.png')  创建一副图片对象
canvas.create_image(200,0,anchor='n',image=image_file) 使用create_image方法在Canvas上显示图片
canvas.pack(side='top') 部署Canvas

就像QQ登录界面中有一个企鹅图片一样,这里也可以在你的GUI初始界面中布置一个你自己的图片。

#各种文本 
Label(window,text='Welcome',font=('Arial',16)).pack() Label(window,text='Username:',font=('Arial',14)).place(x=10,y=170) Label(window,text='Password:',font=('Arial',14)).place(x=10,y=210)

这三行是文本,第一行是紧贴着图片下的一个常见的介绍文本。第二行和第三行的文本分别部署在Username和Password输入框之前,可以让用户知道这个输入框是干什么用的。

⑤、⑥

复制代码
#用户输入框
var_usr_name=StringVar()
var_usr_name.set('example@python.com')
entry_usr_name=Entry(window,textvariable=var_usr_name,font=('Arial',14))
entry_usr_name.place(x=120,y=175)
#密码输入框
var_usr_pwd=StringVar()
entry_usr_pwd=Entry(window,textvariable=var_usr_pwd,font=('Arial',14),show='*')
entry_usr_pwd.place(x=120,y=215)
复制代码

两个输入框,分别是用户名和密码。

如果想要在第一次打开界面时在输入框内显示默认的字符时,就要用到textvariable参数,该参数承接一个StringVar变量,这种变量要想设置或者获取值,需要用到方法getset,而不能简单地用赋值号。

※※另外,关于textvariable需要补充的是,不论是否显示输入框中的默认值,都要设置这个参数,因为这个参数接收了输入框中输入的数值,不设置这个参数的话,输入到输入框中的值就不会保存下来。在以后要用到输入值的时候,通过StringVar类的get、set方法进行。

最后,如果不想明文显示输入的内容(比如输入的密码),可以通过设置show参数实现。

复制代码
def usr_login():
    #下边两行代码就是获取用户输入的username和password
    usr_name=var_usr_name.get()    (1)
    usr_pwd=var_usr_pwd.get()

    #设置异常捕获,当我们第一次访问用户信息文件时是不存在的,所以之而立设置异常捕获
    try:
        with open('usrs_info.pickle','rb') as usr_file:  (2)
            usrs_info=pickle.load(usr_file)
    except FileNotFoundError:
        #这里是当我们没有读取到usr_file时候,程序会创建一个usr_file的文件
        #并且将管理员的用户和密码输入,即用户名和密码均为'admin'
        with open('usrs_info.pickle','wb')as usr_file:    (3)
            usrs_info={'admin':'admin'}
            pickle.dump(usrs_info,usr_file)
    if usr_name in usrs_info:
        if usr_pwd == usrs_info[usr_name]:          (4)
            messagebox.showinfo(title='Welcome',message='How are you? '+usr_name)
        else:
            messagebox.showerror(message='Error,your password is wrond,try again.')
    else:                              (5)
        is_sign_up=messagebox.askyesno('Welcome!','You have not signed up yet. Sign up please!')
        if is_sign_up:
            usr_sign_up()

def usr_sign_up():
    def sign_to_Le_Website():                  (6)
        #以下三行就是获取我们注册时候输入的信息
        np=new_pwd.get()                     (7)
        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)       (8)
        #判断两次密码是否输入一致
        if np!=npf:                        (9)
            messagebox.showerror('Error','Password and confirm password must be the same')
        #如果用户名已经在我们的数据文件中,则提示Error,用户已注册
        elif nn in exist_usr_info:
            messagebox.showerror('Error','The user has already signed up!')
        #输入正确时
        else:
            exist_usr_info[nn]=np                (10)
            with open('usrs_info.pickle','wb') as usr_file:
                pickle.dump(exist_usr_info,usr_file)
            messagebox.showinfo('Welcome','You have successfully signed up!')
            window_sign_up.destroy()              (11)

    window_sign_up=Toplevel(window)               (12)
    window_sign_up.geometry('300x200')
    window_sign_up.title('Sign up window')

    new_name=StringVar()
    new_name.set('example@python.com')
    Label(window_sign_up,text='Username:').place(x=10,y=10)
    entry_new_name=Entry(window_sign_up,textvariable=new_name)
    entry_new_name.place(x=130,y=10)

    new_pwd=StringVar()                      (13)
    Label(window_sign_up,text='Password:').place(x=10,y=50)
    entry_usr_pwd_confirm=Entry(window_sign_up,textvariable=new_pwd,show='*')
    entry_usr_pwd_confirm.place(x=130,y=50)

    new_pwd_confirm=StringVar()
    Label(window_sign_up,text='Confirm Password:').place(x=10,y=90)
    entry_usr_pwd_confirm=Entry(window_sign_up,textvariable=new_pwd_confirm,show='*')
    entry_usr_pwd_confirm.place(x=130,y=90)

    btn_confirm_sign_up=Button(window_sign_up,text='Sign up',command=sign_to_Le_Website)
    btn_confirm_sign_up.place(x=180,y=120)           (14)
复制代码

这一部分是功能函数的实现,包括登录和注册功能。这两项也是下边⑨部分设置的两个按钮的响应函数。由于这一部分函数内容涉及较多,依旧拆分为小块说明。

(1)

usr_name=var_usr_name.get()
usr_pwd=var_usr_pwd.get()

var_usr_name、var_usr_pwd分别是⑥中设置的用来承接输入框输入值的两个变量,在创建Entry时通过参数textvariable说明

(2)、(3)

复制代码
    #设置异常捕获,当我们第一次访问用户信息文件时是不存在的,所以之而立设置异常捕获
    try:
        with open('usrs_info.pickle','rb') as usr_file:  (2)
            usrs_info=pickle.load(usr_file)
    except FileNotFoundError:
        #这里是当我们没有读取到usr_file时候,程序会创建一个usr_file的文件
        #并且将管理员的用户和密码输入,即用户名和密码均为'admin'
        with open('usrs_info.pickle','wb')as usr_file:    (3)
            usrs_info={'admin':'admin'}
            pickle.dump(usrs_info,usr_file)
复制代码

建议打开文件时,除了用with ... as ...语句块,还用try ... except ...语句块,前者可以避免文件没有关闭造成的数据泄露,后者可以预防一些异常。

这里用try ... except ...处理文件不存在时候的情况,处理方式为新建一个文件,并写入一个默认用户信息。

这里用了pickle库的loaddump方法进行序列化反序列化,序列化可以方便传输和保存,此外序列化后的数据为二进制数据,读写时必须标识是二进制读写,即rbwb;另外,读取时必须反序列化,不然显示出来的还是二进制数据。

Python的序列化库pickle可以保存数据的类型,即将一个dict进行序列化后,再进行反序列化,得到的仍是一个dict(这一点很重要)。所以我们用usrs_info保存读进来的数据,usrs_info仍是dict类型

(4)、(5)

复制代码
    if usr_name in usrs_info:
        if usr_pwd == usrs_info[usr_name]:          (4)
            messagebox.showinfo(title='Welcome',message='How are you? '+usr_name)
        else:
            messagebox.showerror(message='Error,your password is wrond,try again.')
    else:                              (5)
        is_sign_up=messagebox.askyesno('Welcome!','You have not signed up yet. Sign up please!')
        if is_sign_up:
            usr_sign_up()
复制代码

usrs_info是(2)部分读入的用户信息,由于进行了反序列化,所以可以还原写入前的数据类型,即Dict,所以判断输入的用户名是否为其中的某个Key可以用in关键字。

所有用户的信息都以{'Username' : 'Password'}的字典形式保存在了变量usrs_info中,访问某个Username时,可以直接用usrs_info[ Username ]的方式,这样就可以取得需要用户名对应的密码了,这也是上文判断输入密码是否与该用户对应密码的方式:

if usr_pwd == usrs_info[usr_name]: 

这种通过序列化和反序列化的方式无损存储数据类型的方式是很有用的。

 

当判断完毕之后,就可以通过弹出信息框的方式直观说明了,关于messagebox的几种形式,可以见tkinter(二)部分的内容。这里只补充一下messagebox生成消息弹出框时最常用的参数设置:

messagebox.showxxx(title='xxx',message='xxx')

titlemessage,分别给出了弹出框的标题内容

而以ask开头的弹出框,还会返回一个bool值,当勾选“确认”时,返回True,勾选“取消”时,返回False。可以以此法收集用户消息,进而进行下一步的处理。比如上文中用is_sign_up变量承接,就可以通过该值判断用户是否选择了注册,如果是,则进行注册功能,否的话,就继续原程序执行了。

(6)

def usr_sign_up():
    def sign_to_Le_Website():                 

这里是注册函数usr_sign_up,负责注册界面生成和注册功能实现。注册功能实现用函数sign_to_Le_Website,之所以功能实现函数写的这么靠前,是因为函数调用必须要在其实现之后。由于在(14)部分调用了该函数作为button的响应函数,所以该函数必须在(14)之前实现。

(7)——(11)都是sign_to_Le_Website的内容,由于其中的一些变量用到了一些外部变量(比如一些输入框传入的变量),所以建议先看(8)——(14)部分,这一部分为注册界面的实现

(7)

        np=new_pwd.get()                     
        npf=new_pwd_confirm.get()
        nn=new_name.get()

这三个变量为从(13)部分建立的三个输入框传入的三个用户输入值,分别表示欲创建的用户名、密码和确认密码

(8)

        #打开我们记录数据的文件,将注册信息读出
        with open('usrs_info.pickle','rb') as usr_file:
            exist_usr_info=pickle.load(usr_file)      

从用户文件中将已有的用户信息读入,以便进行后续判断。

(9)、(10)

复制代码
        if np!=npf:                        (9)
            messagebox.showerror('Error','Password and confirm password must be the same')
        #如果用户名已经在我们的数据文件中,则提示Error,用户已注册
        elif nn in exist_usr_info:
            messagebox.showerror('Error','The user has already signed up!')
        #输入正确时
        else:
            exist_usr_info[nn]=np                (10)
            with open('usrs_info.pickle','wb') as usr_file:
                pickle.dump(exist_usr_info,usr_file)
            messagebox.showinfo('Welcome','You have successfully signed up!')
复制代码

这部分是检验输入内容是否合法,三个判断语句分别表示三种情况:密码和确认密码不同、用户名已存在、输入正确;

对不同情况进行分别处理,前两种情况均属于异常情况,用弹出框标识即可,并不需要做额外的处理;

正确情况下,就需要向用户文件中写入新注册的用户信息:先为用户信息Dict添加一项,给Dict添加一项的方式很简单,并不像List那样还需要用到append方法,而是直接用 dict [ 'new_name' ] = 'new_pwd'即可完成添加。之后再通过序列化方式将更新后的用户信息dict保存到文件中即可,最后再通过弹出框向用户标识已经成功注册。

(11)

window_sign_up.destroy() 

注册完成后,注册窗口就没必要再存在了,使用destroy()方法销毁。及时销毁程序运行过程中产生的子功能窗口对于提高用户体验很有帮助。

(12)——(14)

复制代码
   window_sign_up=Toplevel(window)               (12)
    window_sign_up.geometry('300x200')
    window_sign_up.title('Sign up window')

    new_name=StringVar()
    new_name.set('example@python.com')
    Label(window_sign_up,text='Username:').place(x=10,y=10)
    entry_new_name=Entry(window_sign_up,textvariable=new_name)
    entry_new_name.place(x=130,y=10)

    new_pwd=StringVar()                      (13)
    Label(window_sign_up,text='Password:').place(x=10,y=50)
    entry_usr_pwd_confirm=Entry(window_sign_up,textvariable=new_pwd,show='*')
    entry_usr_pwd_confirm.place(x=130,y=50)

    new_pwd_confirm=StringVar()
    Label(window_sign_up,text='Confirm Password:').place(x=10,y=90)
    entry_usr_pwd_confirm=Entry(window_sign_up,textvariable=new_pwd_confirm,show='*')
    entry_usr_pwd_confirm.place(x=130,y=90)

    btn_confirm_sign_up=Button(window_sign_up,text='Sign up',command=sign_to_Le_Website)
    btn_confirm_sign_up.place(x=180,y=120)          (14)
复制代码

(12)

由于要额外生成一个界面,所以利用Toplevel生成额外一个弹窗,创建方式与其他的控件类似,也可以通过titlegeometry进行标题和形状设置。

(13)

这一部分生成了三个输入框及这三个输入框之前的说明文本,生成方式和⑤、⑥部分所述完全相同,这里不再赘述

(14)

生成了一个利用输入的用户名和密码进行注册的按钮,点击该按钮即可实现输入内容登记到用户文件中,响应函数为sign_to_Le_Website,正是该函数完成了登记功能。下面我们就可以回头看(7)——(11)部分关于函数内容的详细说明了。

 

#登录与注册按钮,关联函数  ⑧
btn_login=Button(window,text='Login',command=usr_login)
btn_login.place(x=120,y=240)
btn_sign_up=Button(window,text='sign_up',command=usr_sign_up)
btn_sign_up.place(x=200,y=240)

 

在主界面上创建两个按钮,分别实现两个功能:登录和注册,分别用对应的功能函数来实现。

 

 

#运行主框架    ⑨
window.mainloop()

 

每个GUI程序运行时,都必须使主窗口一直运行,所以这句话是每个GUI程序都要有的。

 

posted @   ShineLe  阅读(304)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
历史上的今天:
2020-03-24 C++ VECTOR容器
点击右上角即可分享
微信分享提示