Python:GUI库tkinter(二)
阅读原文时间:2023年07月10日阅读:3

学习自:

Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) - 洪卫 - 博客园

Tkinter简明教程 - 知乎

TkDocs_官方文档

一个Tkinter库较为全面的总结,很细致!

一个在Tkinter中使用time实现界面快速刷新的例子

1、控件

这一部分已经在前一篇博文说过了,此处额外补充说明一些控件

控件

说明

Canvas

画布。这个部件可以用来绘制图表和图,创建图形编辑器,实现定制窗口部件

CheckButton

单选框。代表一个变量,它有两个不同的值,根据按钮是否点击会在这两个值之间切换。

Combobox

下拉组合框

Entrt

输入框

Spinbox

可选输入控件

Frame

框架。框架有边框和背景,当创建一个应用程序或者dialog时,框架被用来组织其它的窗口部件。

Label

显示一个文本或图片

Menu

菜单条。

Menubutton

菜单按钮

Message

一个可调整文本,能够自动调整文本到给定的宽度或者比率。

Radiobutton

多个选项,选择其中之一。被选中的选项将作为这个控件代表变量的值,并且清除与这一变量相关的其他Radiobutton

Scale

允许通过一个滑块设置一个数字

Scrollbar

配合Canvas、Entry、Listbox、Text部件使用的滚动条

Text

格式化文本显示。允许用不同的格式和属性来显示和编辑文本,同时支持内嵌图像和窗口。

ScrolledText

滚动条文本框,(超出范围时可以上下拖动滚动条)

Toplevel

一个单独的、最上边的窗口显示。

Progressbar

进度条

filedialog

文件对话框

messageBox

消息框

Tkinter中窗口部件类没有分级,所有的窗口部件类在树中都是兄弟关系。

所有这些窗口部件提供了Misc和几何管理方法、配置管理方法和部件自己定义的另外的方法。此外,Toplevel类也提供了窗口管理接口,这意味着一个典型的窗口部件提供了大约150种方法。

2、实践

①主窗口与Label

from tkinter import *

1、实例化Object,建立窗口window

window = Tk()

2、给窗口起名字,用title方法

window.title('My Window')

3、设置窗口的大小,用geometry方法

window.geometry('500x300') # 这里是字母x

#4、在界面上设置Label
L = Label(
window, text='你好!This is Tkinter', bg='green',
font=('Arial', 12), width=30, height=10
)
#说明:bg为背景,font为字体,width与height的单位为字符

#5、部署Label
L.pack() #未设置参数时,自动调节尺寸
#部署Label的方法有pack()和place()两种

#6、主窗口window循环显示
window.mainloop()

测试效果:

②Button

Button是一个标准Tkinter窗口部件,用于实现各种按钮。按钮可以包含文本或者图像。如果将按钮与某个函数(通过command参数)相关联。当这个按钮被按下时,Tkinter自动调用相关联的函数或者方法。

按钮仅能显示一种字体,但是这个文本可以跨行。另外,文本中的字母可以有下划线,例如标明该按钮功能对应的快捷键。默认情况下,Tab键用于将焦点移动到一个按钮部件。

按钮通常在工具条中或应用程序窗口中,并且用来接收或者忽略输入在对话框中的数据。关于按钮和输入数据的配合,可以参看Checkbutton和Radiobutton部件。

创建Button

按钮创建时,需要指定按钮的内容(文本、位图、图像)和一个当前按钮被按下时的回调函数:

b = tkinter.Button(window , text='hit me',command=hit_me)

可以创建一个什么都不做的按钮,只需要把回调函数command = DISABLED

例子

from tkinter import *

1、实例化Object,建立窗口window

window = Tk()

2、窗口名

window.title('My Window')

3、设置窗口大小

window.geometry('500x300')

4、在图形界面上设置标签

将Label标签的内容设置为字符类型,用var来接受hit_me函数传出内容

用以显示在标签上

var = StringVar()
L = Label(
window, textvariable=var,
bg='green', fg='white',
font=('arial', 12),
width=30, 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('')

5、设置Button按钮

b = Button(
window, text='hit me', font=('Arial', 12),
width=10, height=1, command=hit_me
)
b.pack()

6、主窗口循环展示

window.mainloop()

③Entry:单行文本输入框

例子

from tkinter import *

window = Tk()
window.title('My Window')
window.geometry('300x500')

e1=Entry(window,show='*',font=('Arial',14))#显示成密文形式
e2=Entry(window,font=('Arial',14))#显示成明文形式
e1.pack()
e2.pack()

window.mainloop()

④Text:多行文本

https://www.jianshu.com/p/bf3b49c66801?from=singlemessage

Text是一个多行文本区域,显示多行文本,可以用来收集用户输入的文字,格式化文本显示。

例子

from tkinter import *

window = Tk()
window.title('My Window')
window.geometry('500x300')

e = Entry(window)
e.pack()

定义按钮的事件函数insert_point与insert_end

def insert_point(): # 在鼠标焦点处插入输入内容
var = e.get()
t.insert('insert', var)

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

B1 = Button(
window, text='Insert_Point', width=10,
height=2, command=insert_point
)
B1.pack()
B2=Button(
window,text='Insert_End',width=10,
height=2,command=insert_end
)
B2.pack()

t = Text(window,height=3)
t.pack()

window.mainloop()

⑤Listbox:列表框

相关参数、方法:https://blog.csdn.net/qq_41556318/article/details/85108351

https://blog.csdn.net/aa1049372051/article/details/51878578

主要方法:

curselection:返回选中选项的序号

delete:删除一些项

insert:插入一些项

size:选中的数量

提供一个由很多选项组成的列表,可以从中选择需要的项

from tkinter import *

window=Tk()
window.title('My Window')
window.geometry('500x300')

#创建一个Label
var1=StringVar()
L=Label(window,bg='green',fg='yellow',font=('Arial',12),
width=10,textvariable=var1)
L.pack()

def print_selection():
value = lb.get(lb.curselection())
var1.set(value)

b1=Button(window,text='Print Selection',width=15,
height=2,command=print_selection)
b1.pack()

var2=StringVar()
var2.set((1,2,3,4))
lb=Listbox(window,listvariable=var2)
list_items=[11,22,33,44]
for item in list_items:
lb.insert('end',item) #从最后一个位置开始插入
lb.insert(1,'first')
lb.insert(2,'second')
lb.delete(2)
lb.pack()
window.mainloop()

为ListBox绑定事件,使得我们在选中其中某一项时触发该事件:

def func():
pass

lb=ListBox(…).place(…)
lb.bind('',func)

这段代码的意思是,当双击其中某一项时,调用函数func

由于ListBox没有command参数,所以不能用command与方法绑定,而是直接用bind和事件以及事件响应函数绑定,这样当相应事件触发时就能调用该响应函数。

⑥Radiobutton:多值单选

from tkinter import *

window=Tk()
window.title('My Window')
window.geometry('500x300')

var=StringVar()
l=Label(window,bg='yellow',width=20,text='empty')
l.pack()

def print_selection():
l.config(text='you have selected'+var.get())

#创建三个radiobutton选项
#其中variable=var,value='A'说明:

选择了该项,那么变量var则赋值为'A'

r1=Radiobutton(window,text='option A',variable=var,value='A',
command=print_selection)
r1.pack()
r2=Radiobutton(window,text='option B',variable=var,value='B',
command=print_selection)
r2.pack()
r3=Radiobutton(window,text='option C',variable=var,value='C',
command=print_selection)
r3.pack()

window.mainloop()

⑦Checkbutton:多选按钮

from tkinter import *

window=Tk()
window.title('My Window')
window.geometry('500x300')

l=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=IntVar()
var2=IntVar()
c1=Checkbutton(window,text='Python',variable=var1,onvalue=1,offvalue=0,command=print_selection)
c2=Checkbutton(window,text='C++',variable=var2,onvalue=1,offvalue=0,command=print_selection)
c1.pack()
c2.pack()

window.mainloop()

⑧Scale:刻度滑块、动态取值

from tkinter import *

window = Tk()
window.title('My Window')
window.geometry('500x300')

l = Label(window, bg='green', fg='white', width=20, text='empty')
l.pack()

def print_selection(v):
l.config(text='You have selected ' + v)

s = Scale(window, from_=0, to=10, orient=HORIZONTAL,
length=200, showval=0, tickinterval=2,
resolution=0.01, command=print_selection)
s.pack()
window.mainloop()

⑨Canvas:画布

提供绘图功能(直线、椭圆、多边形、矩形),可以包含图形或者位图,用来绘制图标和图,创建图形编辑器,实现定制窗口部件

什么时候用:比如用户交互界面等,需要提供设计的图标、图形、logo等信息可以用到画布Canvas

from tkinter import *

window = Tk()
window.title('My Window')
window.geometry('500x300')

canvas=Canvas(window,bg='green',width=500,height=200)
image_file=PhotoImage(file='Squirrel.png')
image=canvas.create_image(250,0,anchor='n',image=image_file)
#定义多边形参数,然后在画布上画出指定图形
x0,y0,x1,y1=100,100,150,150
line=canvas.create_line(x0-50,y0-50,x1-50,y1-50)
oval=canvas.create_oval(x0+120,y0+50,x1+120,y1+50,fill='yellow')
arc=canvas.create_arc(x0,y0+50,x1,y1+50,start=0,extent=180)
rect=canvas.create_rectangle(330,30,330+20,30+20)
canvas.pack()

def moveit():
canvas.move(rect,2,2) #移动正方形rect

b=Button(window,text='move item',command=moveit).pack()
window.mainloop()

使用canvas.move(xxx,x,y),可以移动画布上的对象xxx

⑩Menu:工具栏菜单条

from tkinter import *

window = Tk()
window.title('My Window')
window.geometry('500x300')

l=Label(window,text=' ',bg='green')
l.pack()

counter=0
def do_job():
global counter
l.config(text='do '+str(counter))
counter+=1

#创建一个菜单栏,我们可以把它理解为一个容器,在窗口的上方
menubar=Menu(window)
#创建一个File菜单项(默认不下拉,下拉内容包括New,Open,Save,Exit功能项)
filemenu=Menu(menubar,tearoff=1)
#将上面定义的控菜单命名为File,放入菜单栏中,即装入那个容器中
menubar.add_cascade(label='File',menu=filemenu)

#在File中加入New、Open、Save等小彩蛋,即我们平常看到的
#下拉菜单,每一个小菜单对应命令操作
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()#添加一条分割线
#tkinter库中的quit函数用于退出
filemenu.add_command(label='Exit',command=window.quit)

#创建一个Edit菜单项,默认下拉,下拉内容包括Cut、Copy、Paste
editmenu=Menu(menubar,tearoff=1)
#将上面定义的控菜单命名为Edit,放在菜单栏中
menubar.add_cascade(label='Edit',menu=editmenu)

#同样在Edit中加入Cut、Copy、Paste等小命令功能单元,如果
#点击这些单元,就会触发do_fob的功能
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=Menu(filemenu)
filemenu.add_cascade(label='Import',menu=submenu,underline=0)
#创建三级菜单
submenu.add_command(label='SubMenu_1',command=do_job)

window.config(menu=menubar)
window.mainloop()

⑪Frame:窗口

用来承载其它GUI元素,是一个在Windows上分离小区域的部件,它能将Windows分成不同的区,然后存放不同的其他部件,同一个Frame上也能够再分成两个Frame

使用时机:

在像软件或者网页交互界面等,有不同的界面逻辑层级和功能区域划分时可以用到,让交互界面逻辑更加清晰。

from tkinter import *

window=Tk()
window.title('My Window')
window.geometry('300x500')

#创建一个Label用以显示内容并且放置
Label(window,text='on the window',bg='red',font=('Arial',16)).pack()

#创建一个主Frame
frame=Frame(window)
frame.pack()

#创建次级Frame,放置在主Frame之上
framel=Frame(frame)#左frame
framer=Frame(frame)
framel.pack(side='left')
framer.pack(side='right')

#创建三组Label,为次级Frame中的内容,分为左右区域
#用不同颜色标识
Label(framel,text='on the framel1',bg='green').pack()
Label(framel,text='on the framel2',bg='green').pack()
Label(framel,text='on the framel3',bg='green').pack()
Label(framer,text='on the framer1',bg='yellow').pack()
Label(framer,text='on the framer2',bg='yellow').pack()
Label(framer,text='on the framer3',bg='yellow').pack()
window.mainloop( )

⑫messagebox:消息框

使用消息框之前需要首先定义一个触发器,来触发这个弹窗,比如button按钮,通过触发器触发,调用messagebox,这样点击button按钮就可以弹出该对话框。下面给出messageBox提示信息的

messagebox提示信息的几种形式

messagebox.showinfo(title='Hi',message='你好!') #提示
messagebox.showwarning(title='Hi',message='警告!')#警告
messagebox.showerror(title='Hi',message='错误!') #错误
print(messagebox.askquestion(title='Hi',message='你好!'))#选择对话框,返回值为'yes'或'no'
print(messagebox.askyesno(title='Hi',message='你好!'))#返回True和False
print(messagebox.askokcancel(title='Hi',message='你好!'))#返回True和False

不管什么messagebox,最常用的方式是给一个title和message参数,分别标识题目和内容

案例:

from tkinter import *
from tkinter import messagebox

window=Tk()
window.title('My Window')
window.geometry('300x500')
def hit_me():
messagebox.showinfo(title='Hi',message='你好')

Button(window,text='hit me',bg='green',font=('Arial',12)
,command=hit_me).pack()
window.mainloop()

⑬部件部署方法:pack/grid/place

可以用这三种方法在窗口中指定位置处部署某个部件

1)grid

grid是方格,所有的内容都会被放置在这些方格中。例如:

from tkinter import *

window=Tk()
window.title('My Window')
window.geometry('300x500')

for i in range(3):
for j in range(3):
Label(window,text=1).grid(row=i,column=j,padx=10,pady=10,ipadx=10,ipady=10)

window.mainloop() 

2)pack

pack方法按照上下左右的方式进行排列,具体位置通过输入参数side的值实现

from tkinter import *

window=Tk()
window.title('My Window')
window.geometry('300x500')

Label(window,text='p',fg='red').pack(side='top')
Label(window,text='p',fg='red').pack(side='bottom')
Label(window,text='p',fg='red').pack(side='left')
Label(window,text='p',fg='red').pack(side='right')

window.mainloop()

3)place

根据精确的坐标位置来定位,例如

Label(window,text='P1',font=('Arial',20)).place(x=50,y=100,anchor='nw')

就是将该部件放置在坐标为(x=50,y=100)的位置处,而参数anchor表示锚点位置(即原点位置)

⑭Combobox:下拉组合框

使用前要先从tkinter.ttk导入

from tkinter import *
from tkinter.ttk import *
window=Tk()
window.title('My window')
window.geometry('500x300')
combo=Combobox(window)
combo['values']=(1,2,3,4,5,'Text')
combo.current(1)
combo.pack()
window.mainloop()

current方法用以设置默认显示的数值

如果要提取被选中的项,可以通过get方法——combo.get()

⑮ScrolledText:滚动条文本框,(超出范围时可以上下拖动滚动条)

使用前要先从tkinter.scrolledtext中导入

from tkinter import scrolledtext as st
from tkinter import Tk
window=Tk()
window.title('My window')
window.geometry('500x300')
txt=st.ScrolledText(window,width=40,height=10) #需要指定文本区的长宽,否则会占据整个窗口
txt.pack()
window.mainloop()

还有另外两个实用方法:insert与delete

txt.insert(INSERT,'Text') #插入
txt.delete(1.0,END)#删除

⑯Spinbox:可选输入控件

spin = Spinbox(window , from_= 0 , to = 100 , width = 5)

通过from_与to指定范围,width指定控件宽度

from tkinter import Spinbox,Tk
window=Tk()
window.title('My window')
window.geometry('500x300')

spin=Spinbox(window,from_=0,to=100)
spin.pack()
window.mainloop()

⑰Progressbar:进度条

要从tkinter.ttk导入

进度条值的设置:bar['value']

通过动态设置该值,就可以实现动态进度条的功能了

from tkinter import Tk,ttk
from tkinter.ttk import Progressbar
window=Tk()
window.title('My window')
window.geometry('500x300')

style=ttk.Style()
style.theme_use('default')
style.configure('black.Horizontal.TProgressbar',background='black')
bar=Progressbar(window,length=200,style='black.Horizontal.TProgressbar')
bar['value']=70
bar.pack()
window.mainloop()

⑱filedialog:文件对话框

1)创建文件对话框,选择文件并保存路径

from tkinter import filedialog
file=filedialog.askopenfilename()

askopenfilename():选择一个并打开后,file变量会保存该文件的路径。

如果想一次选择多个文件并打开,我们可以用askopenfilenames:

files= filediaglog.askopenfilenames()

指定文件类型:参数filetypes;只需要在元组中指定扩展名即可。

file = filedialog.askopenfilename( filetypes = (('Text files','*.txt'),('all files','*')))

askdirectory():打开目录

指定初始目录:参数initialdir

下边的代码,展示了文件对话框与按钮组合的情况,是一种很常见的方式:

def clicked():
file=filedialog.askopenfilenames(initialdir=os.path.dirname(__file__))
btn=Button(window,text='打开文件夹',command=clicked)

⑲⑳

⑭综合,用户登录窗口的例子

编写一个用户登录界面,用户可以登录账户信息,如果账户已经存在,可以直接登录,登录名或者登录密码输入错误时会提示,如果账户不存在,则提示用户注册,点击注册进去注册界面,输入注册信息,确定后便返回登录界面进行登录

from tkinter import *
from tkinter import messagebox
import pickle

window=Tk()
window.title('Welcome to my first tkinter program!')
window.geometry('400x300')

#加载welcome image
canvas=Canvas(window,width=400,height=135,bg='green')
image_file=PhotoImage(file='Squirrel.png')
image=canvas.create_image(200,0,anchor='n',image=image_file)
canvas.pack(side='top')
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)

#用户登录输入框
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)

#定义用户登录功能
def usr_login():
#下边两行代码就是获取用户输入的username和password
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'  
    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\]:  
        messagebox.showinfo(title='Welcome',message='How are you? '+usr\_name)  
    else:  
        messagebox.showerror(message='Error,your password is wrond,try again.')  
else:  
    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():
#以下三行就是获取我们注册时候输入的信息
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:  
        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  
        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()

window\_sign\_up=Toplevel(window)  
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()  
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)

#login和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()

补充:

StringVar变量值的获取:var.get();设置:var.set('xxx')