1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > Python-Tkinter图形化界面设计

Python-Tkinter图形化界面设计

时间:2018-12-08 06:19:50

相关推荐

Python-Tkinter图形化界面设计

综合了以下的文章:

转载自:/shwee/p/9427975.html

转载自:/p/91844c5bca78

目录

一.图形化界面设计的基本理解二.Tkinter是什么三.窗体控件1) 数据集导入2) Tkinter 控件详细介绍1. Tkinter 模块元素简要说明2. 控件的共同属性3. 控件布局3.1 pack()方法3.2 grid()方法3.3 place()方法 4. tkinter常见控件的用法和特征属性4.1 文本输入和输出相关控件4.1.1 标签(Label)和 消息(Message)4.1.2 文本框(Text)4.1.3 输入框(Entry) 4.2 按钮相关控件4.2.1 按钮(Button)4.2.2 单选按钮(Radiobutton)4.2.2 复选框(Checkbutton)4.3.1 列表框(Listbox)4.3.2 组合框(Combobox) 4.4 滑块(Scale)4.5 菜单(Menu)4.6 子窗体4.7 模式对话框(Modal)4.7.1 交互对话框4.7.2 文件选择对话框4.7.3 颜色选择对话框 4.8 窗口部件4.8.1 Canvas窗口部件4.8.2 Frame 窗口部件 四. 事件响应五. 综合练习,用户登录窗口例子

一.图形化界面设计的基本理解

当前流行的计算机桌面应用程序大多数为图形化用户界面(Graphic User Interface,GUI),即通过鼠标对菜单、按钮等图形化元素触发指令,并从标签、对话框等图型化显示容器中获取人机对话信息。

Python自带了tkinter 模块,实质上是一种流行的面向对象的GUI工具包 TK 的Python编程接口,提供了快速便利地创建GUI应用程序的方法。其图像化编程的基本步骤通常包括:

导入 tkinter 模块创建 GUI 根窗体添加人机交互控件并编写相应的函数。在主事件循环中等待用户触发事件响应。

二.Tkinter是什么

Tkinter 是使用 python 进行窗口视窗设计的模块。Tkinter模块(“Tk 接口”)是Python的标准Tk GUI工具包的接口。作为 python 特定的GUI界面,是一个图像的窗口,tkinter是python 自带的,可以编辑的GUI界面,我们可以用GUI 实现很多直观的功能,比如想开发一个计算器,如果只是一个程序输入,输出窗口的话,是没有用户体验的。所有开发一个图像化的小窗口,就是必要的。

对于稍有GUI编程经验的人来说,Python的Tkinter界面库是非常简单的。python的GUI库非常多,选择Tkinter,一是最为简单,二是自带库,不需下载安装,随时使用,三则是从需求出发,Python作为一种脚本语言,一种胶水语言,一般不会用它来开发复杂的桌面应用,它并不具备这方面的优势,使用Python,可以把它作为一个灵活的工具,而不是作为主要开发语言,那么在工作中,需要制作一个小工具,肯定是需要有界面的,不仅自己用,也能分享别人使用,在这种需求下,Tkinter是足够胜任的!

这篇文章主要做一个简单概述和实践编程,对于从没有接触过GUI的新手,在脑中树立一个基本的界面编程概念,同时自己也能学会如何简单的实现一些小的图形窗口功能。

对于Tkinter编程,可以用两个比喻来理解:

第一个,作画。我们都见过美术生写生的情景,先支一个画架,放上画板,蒙上画布,构思内容,用铅笔画草图,组织结构和比例,调色板调色,最后画笔勾勒。相应的,对应到tkinter编程,那么我们的显示屏就是支起来的画架,根窗体就是画板,在tkinter中则是Toplevel,画布就是tkinter中的容器(Frame),画板上可以放很多张画布(Convas),tkinter中的容器中也可以放很多个容器,绘画中的构图布局则是tkinter中的布局管理器(几何管理器),绘画的内容就是tkinter中的一个个小组件,一幅画由许多元素构成,而我们的GUI界面,就是有一个个组件拼装起来的,它们就是widget。

第二个,我们小时候都玩过积木,只要发挥创意,相同的积木可以堆出各种造型。tkinter的组件也可以看做一个个积木,形状或许不同,其本质都是一样的,就是一个积木,不管它长什么样子,它始终就是积木!所以这些小组件都有许多共性,另外,个人认为,学习界面编程,最重要的不是一开始学习每个积木的样子,不是学习每个组件怎么用,而是这些组件该怎么放。初始学习中,怎么放远远比怎么用重要的多。网上有大量的文章资料,基本全是介绍组件怎么用的,对于怎么放,也就是tkinter中的布局管理器,都是一笔带过,这对初学者有点本末倒置,或许绝大部分是转载的原因吧,极少是自己真正写的。组件怎么用不是最迫切的,用到的时候再去了解也不迟,边用边学反而更好。因此我将专门写一章,详细介绍布局管理器的使用。

三.窗体控件

1) 数据集导入

根窗体是图像化应用程序的根控制器,是tkinter的底层控件的实例。当导入tkinter模块后,调用 Tk()方法可初始化一个根窗体实例 root ,用 title() 方法可设置其标题文字,用geometry()方法可以设置窗体的大小(以像素为单位)。将其置于主循环中,除非用户关闭,否则程序始终处于运行状态。执行该程序,一个窗体就呈现出来了。在这个主循环的根窗体中,可持续呈现中的其他可视化控件实例,监测事件的发生并执行相应的处理程序。下面是根窗体呈现示例:

from tkinter import *root = Tk() # 调用Tk()方法初始化一个根窗体实例root.title('我的第一个Python窗体') # title()方法设置标题文字root.geometry('240x240')# geometry()方法设置窗体大小,这里的乘号不是*,而是小写英文字母xroot.mainloop()

2) Tkinter 控件详细介绍

1. Tkinter 模块元素简要说明

2. 控件的共同属性

在窗体上呈现的可视化控件,通常包括尺寸、颜色、字体、相对位置、浮雕样式、图标样式和悬停光标形状等共同属性。不同的控件由于形状和功能不同,又有其特征属性。在初始化根窗体和根窗体主循环之间,可实例化窗体控件,并设置其属性。父容器可为根窗体或其他容器控件实例。常见的控件共同属性如下表:

标签及常见属性示例:

from tkinter import *root = Tk()lb = Label(root, text = '我是第一个标签', \bg = '#d3fbfb', \fg = 'red', \font = ('华文新魏', 32), \width = 20, \height = 2, \relief = SUNKEN)lb.pack()root.mainloop()

3. 控件布局

控件的布局通常有pack()、grid() 和 place() 三种方法:

3.1 pack()方法

pack()方法是一种简单的布局方法,如果不加参数的默认方式,将按布局语句的先后,以最小占用空间的方式自上而下地排列控件实例,并且保持控件本身的最小尺寸。如下的例子:

用pack() 方法不加参数排列标签。为看清楚各控件所占用的空间大小,文本用了不同长度的中英文,并设置relief = GROOVE的凹陷边缘属性。如下所示:

from tkinter import *root = Tk()lbred = Label(root, text = 'Red', fg = 'Red', relief = GROOVE)lbred.pack()lbgreen = Label(root,text="绿色",fg="green",relief=GROOVE)lbgreen.pack()lbblue = Label(root,text="蓝",fg="blue",relief=GROOVE)lbblue.pack()root.mainloop()

使用pack()方法可设置 fill、side 等属性参数。其中,参数fill 可取值:fill=X,fill=Y或fill=BOTH,分别表示允许控件向水平方向、垂直方向或二维伸展填充未被占用控件。参数 side 可取值:side=TOP(默认),side=LEFT,side=RIGHT,side=BOTTOM,分别表示本控件实例的布局相对于下一个控件实例的方位。如下例子:

from tkinter import *root = Tk()lbred = Label(root,text="Red",fg="Red",relief=GROOVE)lbred.pack()lbgreen = Label(root,text="绿色",fg="green",relief=GROOVE)lbgreen.pack(side=RIGHT) # 本控件的布局相对于下一个控件的方位lbblue = Label(root,text="蓝",fg="blue",relief=GROOVE)lbblue.pack(fill=X) # 控件向水平方向填充未被占用控件root.mainloop()

3.2 grid()方法

grid()方法:是基于网格的布局。先虚拟一个二维表格,再在该表格中布局控件实例。由于在虚拟表格的单元中所布局的控件实例大小不一,单元格也没有固定或均一的大小,因此其仅用于布局的定位。pack()方法与grid()方法不能混合使用。

grid()方法常用布局参数如下:

看下面的例子:用grid()方法排列标签,设想有一个3x4的表格,起始行、列序号均为0。将标签lbred 至于第2列第0行;将标签lbgreen置于第0列第1行;将标签lbblue置于第1列起跨2列第2行,占20像素宽。

from tkinter import *# 虚拟一个二维表格root = Tk()lbred = Label(root,text="Red",fg="Red",relief=GROOVE)lbred.grid(column=2,row=0)lbgreen = Label(root,text="绿色",fg="green",relief=GROOVE)lbgreen.grid(column=0,row=1)lbblue = Label(root,text="蓝",fg="blue",relief=GROOVE)lbblue.grid(column=1,columnspan=2,ipadx=20,row=2)root.mainloop()

3.3 place()方法

place()方法:根据控件实例在父容器中的绝对或相对位置参数进行布局。其常用布局参数如下:

利用place()方法配合relx,rely和relheight,relwidth参数所得的到的界面可自适应根窗体尺寸的大小。place()方法与grid()方法可以混合使用。如下例子:利用place()方法排列消息(多行标签)。

from tkinter import *root = Tk()root.geometry('320x240')msg1 = Message(root,text='''我的水平起始位置相对窗体 0.2,垂直起始位置为绝对位置 80 像素,我的高度是窗体高度的0.4,宽度是200像素''',relief=GROOVE)msg1.place(relx=0.2,y=80,relheight=0.4,width=200)root.mainloop()

4. tkinter常见控件的用法和特征属性

4.1 文本输入和输出相关控件

文本的输入与输出控件通常包括:标签(Label)、消息(Message)、输入框(Entry)、文本框(Text)。他们除了前述共同属性外,都具有一些特征属性和功能。

4.1.1 标签(Label)和 消息(Message)

标签(Label)和 消息(Message):除了单行与多行的不同外,属性和用法基本一致,用于呈现文本信息。值得注意的是:属性text通常用于实例在第一次呈现时的固定文本,而如果需要在程序执行后发生变化,则可以使用下列方法之一实现:

用控件实例的configure()方法来改变属性text的值,可使显示的文本发生变化先定义一个tkinter的内部类型变量var=StringVar() 的值也可以使显示文本发生变化

看下面的一个例子:制作一个电子时钟,用root的after()方法每隔1秒time模块以获取系统当前时间,并在标签中显示出来。

方法一:利用configure()方法或config()来实现文本变化。

import tkinterimport timedef gettime():timestr = time.strftime("%H:%M:%S")# 获取当前时间并转换为字符串lb.configure(text = timestr) # 重新设置标签文本root.after(1000, gettime)# 每隔1S调用函数 gettime 自身获取时间root = tkinter.Tk()root.title('时钟')lb = tkinter.Label(root, text = '', fg = 'blue', font = ("黑体", 80))lb.pack()gettime()root.mainloop()

方法二:利用textvariable变量属性来实现文本变化。

import tkinterimport timedef gettime():var.set(time.strftime("%H:%M:%S")) # 获取当前时间root.after(1000,gettime) # 每隔1s调用函数 gettime 自身获取时间root = tkinter.Tk()root.title('时钟')var=tkinter.StringVar()lb = tkinter.Label(root,textvariable=var,fg='blue',font=("黑体",80))lb.pack()gettime()root.mainloop()

4.1.2 文本框(Text)

文本框的常用方法如下:

上表位置的取值可为整数,浮点数或END(末尾),例如0.0表示第0列第0行如下一个例子:每隔1秒获取一次当前日期的时间,并写入文本框中,如下:本例中调用 datetime.now()获取当前日期时间,用insert()方法每次从文本框txt的尾部(END)开始追加文本。

from tkinter import *import timeimport datetimedef gettime():s=str(datetime.datetime.now())+'\n'txt.insert(END,s)root.after(1000,gettime) # 每隔1s调用函数 gettime 自身获取时间root=Tk()root.geometry('320x240')txt=Text(root)txt.pack()gettime()root.mainloop()

4.1.3 输入框(Entry)

输入框(Entry):通常作为功能比较单一的接收单行文本输入的控件,虽然也有许多对其中文本进行操作的方法,但通常用的只有取值方法get()和用于删除文本的delete(起始位置,终止位置),例如:清空输入框为delete(0,END)。

需要用户输入用户信息时,比如我们平时使用软件、登录网页时,用户交互界面让我们登录账户信息等时候可以用到。

from tkinter import *root = Tk()root.title('My Window')root.geometry('500x300')e1 = Entry(root, show='*', font=('Arial', 14)) # 显示成密文形式e1.pack()e2 = Entry(root, show=None, font=('Arial', 14)) # 显示成明文形式e2.pack()root.mainloop()

4.2 按钮相关控件
4.2.1 按钮(Button)

按钮(Button):主要是为响应鼠标单击事件触发运行程序所设的,故其除控件共有属性外,属性command是最为重要的属性。通常,将按钮要触发执行的程序以函数形式预先定义,然后可以用一下两种方法调用函数。Button按钮的状态有:‘normal’,‘active’,‘disabled’

直接调用函数。参数表达式为“command=函数名”,注意函数名后面不要加括号,也不能传递参数。如下面的command=run1:利用匿名函数调用函数和传递参数。参数的表达式为“command=lambda”:函数名(参数列表)。例如下面的:“command=lambda:run2(inp1.get(),inp2.get())”。

看下面的例子:

从两个输入框去的输入文本后转为浮点数值进行加法运算,要求每次单击按钮产生的算是结果以文本的形式追加到文本框中,将原输入框清空。按钮方法一不传参数调用函数run1()实现,按钮“方法二”用lambda调用函数run2(x,y)同时传递参数实现。

from tkinter import *def run1():a = float(inp1.get())b = float(inp2.get())s = '%0.2f+%0.2f=%0.2f\n' % (a, b, a + b)txt.insert(END, s) # 追加显示运算结果inp1.delete(0, END) # 清空输入inp2.delete(0, END) # 清空输入def run2(x, y):a = float(x)b = float(y)s = '%0.2f+%0.2f=%0.2f\n' % (a, b, a + b)txt.insert(END, s) # 追加显示运算结果inp1.delete(0, END) # 清空输入inp2.delete(0, END) # 清空输入root = Tk()root.geometry('460x240')root.title('简单加法器')lb1 = Label(root, text='请输入两个数,按下面两个按钮之一进行加法计算')lb1.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.1)inp1 = Entry(root)inp1.place(relx=0.1, rely=0.2, relwidth=0.3, relheight=0.1)inp2 = Entry(root)inp2.place(relx=0.6, rely=0.2, relwidth=0.3, relheight=0.1)# 方法-直接调用 run1()btn1 = Button(root, text='方法一', command=run1)btn1.place(relx=0.1, rely=0.4, relwidth=0.3, relheight=0.1)# 方法二利用 lambda 传参数调用run2()btn2 = Button(root, text='方法二', command=lambda: run2(inp1.get(), inp2.get()))btn2.place(relx=0.6, rely=0.4, relwidth=0.3, relheight=0.1)# 在窗体垂直自上而下位置60%处起,布局相对窗体高度40%高的文本框txt = Text(root)txt.place(rely=0.6, relheight=0.4)root.mainloop()

4.2.2 单选按钮(Radiobutton)

单选按钮(Radiobutton):是为了响应故乡排斥的若干单选项的单击事件以触发运行自定义函数所设的,该控件排除具有共有属性外,还具有显示文本(text)、返回变量(variable)、返回值(value)、响应函数名(command)等重要属性。响应函数名“command=函数名”的用法与Button相同,函数名最后也要加括号。返回变量variable=var通常应预先声明变量的类型var=IntVar()或var=StringVar(),在所调用的函数中方可用var.get()方法获取被选中实例的value值。例如下面:

from tkinter import *def Mysel():dic = {0:'甲',1:'乙',2:'丙'}s = "您选了" + dic.get(var.get()) + "项"lb.config(text = s)root = Tk()root.title('单选按钮')lb = Label(root)lb.pack()var = IntVar()rd1 = Radiobutton(root,text="甲",variable=var,value=0,command=Mysel)rd1.pack()rd2 = Radiobutton(root,text="乙",variable=var,value=1,command=Mysel)rd2.pack()rd3 = Radiobutton(root,text="丙",variable=var,value=2,command=Mysel)rd3.pack()root.mainloop()

4.2.2 复选框(Checkbutton)

复选框(Checkbutton) :是为了返回多个选项值的交互控件,通常不直接触发函数的执行。该控件除具有共有属性外,还具有显示文本(text)、返回变量(variable)、选中返回值(onvalue)和未选中默认返回值(offvalue)等重要属性。返回变量variable=var 通常可以预先逐项分别声明变量的类型var=IntVar() (默认)或 var=StringVar(), 在所调用的函数中方可分别调用 var.get()方法 取得被选中实例的 onvalue或offvalue值。复选框实例通常还可分别利用 select()、deselect()和 toggle() 方法对其进行选中、清除选中和反选操作。

如下的例子: 利用复选框实现,单击OK,可以将选中的结果显示在标签上。效果如下:

from tkinter import *import tkinterdef run():if(CheckVar1.get()==0 and CheckVar2.get()==0 and CheckVar3.get()==0 and CheckVar4.get()==0):s = '您还没选择任何爱好项目'else:s1 = "足球" if CheckVar1.get()==1 else ""s2 = "篮球" if CheckVar2.get() == 1 else ""s3 = "游泳" if CheckVar3.get() == 1 else ""s4 = "田径" if CheckVar4.get() == 1 else ""s = "您选择了%s %s %s %s" % (s1,s2,s3,s4)lb2.config(text=s)root = tkinter.Tk()root.title('复选框')lb1=Label(root,text='请选择您的爱好项目')lb1.pack()CheckVar1 = IntVar()CheckVar2 = IntVar()CheckVar3 = IntVar()CheckVar4 = IntVar()ch1 = Checkbutton(root,text='足球',variable = CheckVar1,onvalue=1,offvalue=0)ch2 = Checkbutton(root,text='篮球',variable = CheckVar2,onvalue=1,offvalue=0)ch3 = Checkbutton(root,text='游泳',variable = CheckVar3,onvalue=1,offvalue=0)ch4 = Checkbutton(root,text='田径',variable = CheckVar4,onvalue=1,offvalue=0)ch1.pack()ch2.pack()ch3.pack()ch4.pack()btn = Button(root,text="OK",command=run)btn.pack()lb2 = Label(root,text='')lb2.pack()root.mainloop()

4.3.1 列表框(Listbox)

列表框(Listbox) :可供用户单选或多选所列条目以形成人机交互。列表框控件的主要方法见下面的表:

执行自定义函数时,通常使用“实例名.surselection()” 或 “selected” 来获取选中项的位置索引。由于列表框实质上就是将Python 的列表类型数据可视化呈现,在程序实现时,也可直接对相关列表数据进行操作,然后再通过列表框展示出来,而不必拘泥于可视化控件的方法。

看下面的一个例子:实现列表框的初始化、添加、插入、修改、删除和清空操作,如下:

from tkinter import *def ini():Lstbox1.delete(0,END)list_items = ["数学","物理","化学","语文","外语"]for item in list_items:Lstbox1.insert(END,item)def clear():Lstbox1.delete(0,END)def ins():if entry.get() != '':if Lstbox1.curselection() == ():Lstbox1.insert(Lstbox1.size(),entry.get())else:Lstbox1.insert(Lstbox1.curselection(),entry.get())def updt():if entry.get() != '' and Lstbox1.curselection() != ():selected=Lstbox1.curselection()[0]Lstbox1.delete(selected)Lstbox1.insert(selected,entry.get())def delt():if Lstbox1.curselection() != ():Lstbox1.delete(Lstbox1.curselection())root = Tk()root.title('列表框实验')root.geometry('320x240')frame1 = Frame(root,relief=RAISED)frame1.place(relx=0.0)frame2 = Frame(root,relief=GROOVE)frame2.place(relx=0.5)Lstbox1 = Listbox(frame1)Lstbox1.pack()entry = Entry(frame2)entry.pack()btn1 = Button(frame2,text='初始化',command=ini)btn1.pack(fill=X)btn2 = Button(frame2,text='添加',command=ins)btn2.pack(fill=X)btn3 = Button(frame2,text='插入',command=ins) # 添加和插入功能实质上是一样的btn3.pack(fill=X)btn4 = Button(frame2,text='修改',command=updt)btn4.pack(fill=X)btn5 = Button(frame2,text='删除',command=delt)btn5.pack(fill=X)btn6 = Button(frame2,text='清空',command=clear)btn6.pack(fill=X)root.mainloop()

4.3.2 组合框(Combobox)

组合框(Combobox): 实质上是带文本框的上拉列表框,其功能也将是Python 的列表类型数据可视化呈现,并提供用户单选或多选所列条目以形成人机交互。在图形化界面设计时,由于其具有灵活的界面,因此往往比列表框更受喜爱。但该控件并不包含在 tkinter 模块中,而是与 TreeView、Progressbar、Separator等控件一同包含在tkinter 的子模块ttk中。如果使用该控件,应先与from tkinter import ttk 语句引用ttk子模块,然后创建组合框实例: 实例名=Combobox(根对象,[属性列表])指定变量var=StringVar(),并设置实例属性 textvariable = var,values=[列表…]。组合框控件常用方法有:获得所选中的选项值get()和获得所选中的选项索引current()。

看下面的一个例子:实现四则运算计算器,将两个操作数分别填入两个文本框后,通过选择组合框中的算法触发运算。

from tkinter.ttk import *from tkinter import *def calc(event):a = float(t1.get())b = float(t2.get())dic = {0:a+b,1:a-b,2:a*b,3:a/b}c = dic[comb.current()]lbl.config(text=str(c))root = Tk()root.title('四则运算')root.geometry('320x240')t1 = Entry(root)t1.place(relx=0.1,rely=0.1,relwidth=0.2,relheight=0.1)t2 = Entry(root)t2.place(relx=0.5,rely=0.1,relwidth=0.2,relheight=0.1)var = StringVar()comb = Combobox(root,textvariable=var,values=['加','减','乘','除',])comb.place(relx=0.1,rely=0.5,relwidth=0.2)comb.bind('<<ComboboxSelected>>',calc)lbl=Label(root,text='结果')lbl.place(relx=0.5,rely=0.7,relwidth=0.2,relheight=0.3)root.mainloop()

4.4 滑块(Scale)

滑块(Scale): 是一种直观地进行数值输入的交互控件,其主要属性见下表:

滑块控件实例的主要方法比较简单,有 get()和set(值),分别为取值和将滑块设在某特定值上。滑块实例也可绑定鼠标左键释放事件,并在执行函数中添加参数event来实现事件响应。

例如:在一个窗体上设计一个200像素宽的水平滑块,取值范围为1.0~5.0,分辨精度为0.05,刻度间隔为 1,用鼠标拖动滑块后释放鼠标可读取滑块值并显示在标签上。效果如下:

from tkinter import *def show(event):s = '滑块的取值为' + str(var.get())lb.config(text=s)root = Tk()root.title('滑块实验')root.geometry('320x180')var=DoubleVar()scl = Scale(root,orient=HORIZONTAL,length=200,from_=1.0,to=5.0,label='请拖动滑块',tickinterval=1,resolution=0.05,variable=var)scl.bind('<ButtonRelease-1>',show)scl.pack()lb = Label(root,text='')lb.pack()root.mainloop()

4.5 菜单(Menu)

菜单(Menu):用于可视化地为一系列的命令分组,从而方便用户找到和触发执行这些命令。这里Menu所实例化别的主要是菜单,其通式为:

菜单实例名=Menu(根窗体)菜单分组1=Menu(菜单实例名)菜单实例名.add_cascade(<label=菜单分组1 显示文本>,<menu=菜单分组1>)菜单分组1.add_command(<label=命令1文本>,<command=命令1函数名>)

其中较为常见的方法有:add_cascade()、add_command()和add_separator(),分别用于添加一个菜单分组、添加一条菜单命令和添加一条分割线。

利用Menu控件也可以创建快捷菜单(又称为上下文菜单)。通常需要右击弹出的控件实例绑定鼠标右击响应事件,并指向一个捕获event参数的自定义函数,在该自定义函数中,将鼠标的触发位置event.x_root 和 event.y_root以post()方法传给菜单。

例子:仿照window自带的“记事本”中的文件和编辑 菜单,实现在主菜单个快捷菜单上触发菜单命令,并相应改变窗体上的标签的文本内容。效果如下:

from tkinter import *def new():s = '新建'lb1.config(text=s)def ope():s = '打开'lb1.config(text=s)def sav():s = '保存'lb1.config(text=s)def cut():s = '剪切'lb1.config(text=s)def cop():s = '复制'lb1.config(text=s)def pas():s = '粘贴'lb1.config(text=s)def popupmenu(event):mainmenu.post(event.x_root,event.y_root)root = Tk()root.title('菜单实验')root.geometry('320x240')lb1 = Label(root,text='显示信息',font=('黑体',32,'bold'))lb1.place(relx=0.2,rely=0.2)mainmenu = Menu(root)menuFile = Menu(mainmenu) # 菜单分组 menuFilemainmenu.add_cascade(label="文件",menu=menuFile)menuFile.add_command(label="新建",command=new)menuFile.add_command(label="打开",command=ope)menuFile.add_command(label="保存",command=sav)menuFile.add_separator() # 分割线menuFile.add_command(label="退出",command=root.destroy)menuEdit = Menu(mainmenu) # 菜单分组 menuEditmainmenu.add_cascade(label="编辑",menu=menuEdit)menuEdit.add_command(label="剪切",command=cut)menuEdit.add_command(label="复制",command=cop())menuEdit.add_command(label="粘贴",command=pas())root.config(menu=mainmenu)root.bind('Button-3',popupmenu) # 根窗体绑定鼠标右击响应事件root.mainloop()

4.6 子窗体

子窗体:用Toplevel可新建一个显示在最前面的子窗体,其通式为: 字体实例名=Toplevel(根窗体),子窗体与根窗体类似,也可设置title、geomerty等属性,并在画布上布局其他控件。

如下的例子:在根窗体上创建菜单,触发创建一个新的窗体

from tkinter import *def newwind():winNew = Toplevel(root)winNew.geometry('320x240')winNew.title('新窗体')lb2 = Label(winNew,text='我在新窗体上')lb2.place(relx=0.2,rely=0.2)btClose=Button(winNew,text='关闭',command=winNew.destroy)btClose.place(relx=0.7,rely=0.5)root = Tk()root.title('新建窗体实验')root.geometry('320x240')lb1 = Label(root,text='主窗体',font=('黑体',32,'bold'))lb1.place(relx=0.2,rely=0.2)mainmenu = Menu(root)menuFile = Menu(mainmenu)mainmenu.add_cascade(label='菜单',menu=menuFile)menuFile.add_command(label='新窗体',command=newwind)menuFile.add_separator()menuFile.add_command(label='退出',command=root.destroy)root.config(menu=mainmenu)root.mainloop()

关闭窗体程序运行的方法通常用 destory(),而不建议用 quit()。用Toplevel 所创建的子窗体是非模式(Modeless)的窗体,虽然初建时子窗体在最前面,但根窗体上的控件实例也是可以被操作的。

4.7 模式对话框(Modal)

模式对话框(Modal):是相对于前面介绍的非模式窗体而言的,所弹出的对话框必须应答,在关闭之前无法操作其后面的其他窗体。常见的模式对话框有消息对话框、输入对话框、文件选择对话框、颜色选择对话框等。

4.7.1 交互对话框

(一)、消息对话框:引用 tkinter.messagebox 包,可使用消息对话框函数。执行这些函数,可弹出模式消息对话框,并根据用户的响应但会一个布尔值。其通式为:

消息对话框函数(<title=标题文本>,<message=消息文本>,[其他参数])

看下面的例子:单击按钮,弹出确认取消对话框,并将用户回答显示在标签中。效果如下:

from tkinter import *import tkinter.messageboxdef xz():answer=tkinter.messagebox.askokcancel('请选择','请选择确定或取消')if answer:lb.config(text='已确认')else:lb.config(text='已取消')root = Tk()lb = Label(root,text='')lb.pack()btn=Button(root,text='弹出对话框',command=xz)btn.pack()root.mainloop()

(二)、输入对话框:引用tkinter.simpledialog包,可弹出输入对话框,用以接收用户的简单输入。输入对话框常用 askstring()、askfloat()和askfloat() 三种函数,分别用于接收字符串、整数和浮点数类型的输入。

如下面的例子:单击按钮,弹出输入对话框,接收文本输入显示在窗体的标签上。如下:

from tkinter.simpledialog import *def xz():s=askstring('请输入','请输入一串文字')lb.config(text=s)root = Tk()lb = Label(root,text='')lb.pack()btn=Button(root,text='弹出输入对话框',command=xz)btn.pack()root.mainloop()

4.7.2 文件选择对话框

文件选择对话框:引用tkinter.filedialog包,可弹出文件选择对话框,让用户直观地选择一个或一组文件,以供进一步的文件操作。常用的文件选择对话框函数有 askopenfilename()、askopenfilenames()和asksaveasfilename(),分别用于进一步打开一个文件、一组文件和保存文件。其中,askopenfilename()和asksaveasfilenamme()函数的返回值类型为包含文件路径的文件名字符串,而askopenfilenames()函数的返回值类型为元组。

例如:单击按钮,弹出文件选择对话框(“打开”对话框),并将用户所选择的文件路径和文件名显示在窗体的标签上。如下:

from tkinter import *import tkinter.filedialogdef xz():filename=tkinter.filedialog.askopenfilename()if filename != '':lb.config(text='您选择的文件是'+filename)else:lb.config(text='您没有选择任何文件')root = Tk()lb = Label(root,text='')lb.pack()btn=Button(root,text='弹出文件选择对话框',command=xz)btn.pack()root.mainloop()

4.7.3 颜色选择对话框

颜色选择对话框:引用tkinter.colorchooser包,可使用 askcolor()函数弹出模式颜色选择对话框,让用户可以个性化地设置颜色属性。该函数的返回形式为包含RGB十进制浮点元组和RGB十六进制字符串的元组类型,例如:“((135.527343.52734375,167.65234375,186.7265625)),’#87a7ba’”。通常,可将其转换为字符串类型后,再截取以十六进制数表示的RGB颜色字符串用于为属性赋值。

例如:单击按钮,弹出颜色选择对话框,并将用户所选择的颜色设置为窗体上标签的背景颜色,如下:

from tkinter import *import tkinter.colorchooserdef xz():color=tkinter.colorchooser.askcolor()colorstr=str(color)print('打印字符串%s 切掉后=%s' % (colorstr,colorstr[-9:-2]))lb.config(text=colorstr[-9:-2],background=colorstr[-9:-2])root = Tk()lb = Label(root,text='请关注颜色的变化')lb.pack()btn=Button(root,text='弹出颜色选择对话框',command=xz)btn.pack()root.mainloop()

4.8 窗口部件
4.8.1 Canvas窗口部件

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

在比如像用户交互界面等,需要提供设计的图标、图形、logo等信息是可以用到画布。

from tkinter import *root = Tk()root.title('My Window')root.geometry('500x400')canvas = Canvas(root, bg = 'green', height = 200, width = 500)image_file = PhotoImage(file = 'pic.gif')image = canvas.create_image(250, 0, anchor = 'n', image = image_file)x0, y0, x1, y1 = 100, 100, 150, 150line = 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) # 画扇形 从0度打开收到180度结束rect = canvas.create_rectangle(330, 30, 330 + 20, 30 + 20) # 画矩形正方形canvas.pack()def moveit():canvas.move(rect, 2, 2) # 移动正方形rect(也可以改成其他图形名字用以移动一起图形、元素),按每次(x=2, y=2)步长进行移动b = Button(root, text = 'move item', command = moveit).pack()root.mainloop()

4.8.2 Frame 窗口部件

Frame框架,用来承载放置其他GUI元素,就是一个容器,是一个在 Windows 上分离小区域的部件, 它能将 Windows 分成不同的区,然后存放不同的其他部件. 同时一个 Frame 上也能再分成两个 Frame, Frame 可以认为是一种容器.

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

from tkinter import *root = Tk()root.geometry('500x300')# 在图形界面上创建一个标签用以显示内容并放置Label(root, text='on the window', bg='red', font=('Arial', 16)).pack()# 创建一个主frame,长在主window窗口上frame = Frame(root)frame.pack()# 创建第二层框架frame,长在主框架frame上面frame_l = Frame(frame) # 第二层frame,左frame,长在主frame上frame_r = Frame(frame) # 第二层frame,右frame,长在主frame上frame_l.pack(side='left')frame_r.pack(side='right')# 创建三组标签,为第二层frame上面的内容,分为左区域和右区域,用不同颜色标识Label(frame_l, text='on the frame_l1', bg='green').pack()Label(frame_l, text='on the frame_l2', bg='green').pack()Label(frame_l, text='on the frame_l3', bg='green').pack()Label(frame_r, text='on the frame_r1', bg='yellow').pack()Label(frame_r, text='on the frame_r2', bg='yellow').pack()Label(frame_r, text='on the frame_r3', bg='yellow').pack()# 第8步,主窗口循环显示root.mainloop()

四. 事件响应

用tkinter 可将用户事件与自定义函数绑定,用键盘或鼠标的动作事件来响应触发自定义函数的执行。其通式为:

控件实例.bind(<事件代码>,<函数名>)

其中,事件代码通常以半角小于号“<”和大于号“>” 界定,包括事件和按键等 2~3个部分,它们之间用减号分隔,常见事件代码见下表:

例如,将框架控件实例frame 绑定鼠标右键单击事件,调用自定义函数 myfunc()可表示为"frame.bind(’’,myfunc)",注意: myfunc后面没有括号。将控件实例绑定到键盘事件和部分光标不落在具体控件实例上的鼠标事件时,还需要设置该实例执行focus_set() 方法获得焦点,才能对事件持续响应。例如: frame.focus_set()。所调用的自定义函数若需要利用鼠标或键盘的响应值,可将event作为参数,通过event的属性获取。event的属性见下表:

例如:将标签绑定键盘任意键触发事件并获取焦点,并将按键字符显示在标签上

from tkinter import *def show(event):s=event.keysymlb.config(text=s)root=Tk()root.title('按键实验')root.geometry('200x200')lb=Label(root,text='请按键',font=('黑体',48))lb.bind('<Key>',show)lb.focus_set()lb.pack()root.mainloop()

五. 综合练习,用户登录窗口例子

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

import tkinter as tk # 使用Tkinter前需要先导入import tkinter.messageboximport pickle# 第1步,实例化object,建立窗口windowwindow = tk.Tk()# 第2步,给窗口的可视化起名字window.title('Wellcome to Hongwei Website')# 第3步,设定窗口的大小(长 * 宽)window.geometry('400x300') # 这里的乘是小x# 第4步,加载 wellcome imagecanvas = tk.Canvas(window, width=400, height=135, bg='green')image_file = tk.PhotoImage(file='pic.gif')image = canvas.create_image(200, 0, anchor='n', image=image_file)canvas.pack(side='top')tk.Label(window, text='Wellcome', font=('Arial', 16)).pack()# 第5步,用户信息tk.Label(window, text='User name:', font=('Arial', 14)).place(x=10, y=170)tk.Label(window, text='Password:', font=('Arial', 14)).place(x=10, y=210)# 第6步,用户登录输入框entry# 用户名var_usr_name = tk.StringVar()var_usr_name.set('example@')entry_usr_name = tk.Entry(window, textvariable=var_usr_name, font=('Arial', 14))entry_usr_name.place(x=120, y=175)# 用户密码var_usr_pwd = tk.StringVar()entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, font=('Arial', 14), show='*')entry_usr_pwd.place(x=120, y=215)# 第8步,定义用户登录功能def usr_login():# 这两行代码就是获取用户输入的usr_name和usr_pwdusr_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.close() # 必须先关闭,否则pickle.load()会出现EOFError: Ran out of input# 如果用户名和密码与文件中的匹配成功,则会登录成功,并跳出弹窗how are you? 加上你的用户名。if usr_name in usrs_info:if usr_pwd == usrs_info[usr_name]:tkinter.messagebox.showinfo(title='Welcome', message='How are you? ' + usr_name)# 如果用户名匹配成功,而密码输入错误,则会弹出'Error, your password is wrong, try again.'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 now?')# 提示需不需要注册新用户if is_sign_up:usr_sign_up()# 第9步,定义用户注册功能def usr_sign_up():def sign_to_Hongwei_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)# 这里就是判断,如果两次密码输入不一致,则提示Error, Password and confirm password must be the same!if np != npf:tkinter.messagebox.showerror('Error', 'Password and confirm password must be the same!')# 如果用户名已经在我们的数据文件中,则提示Error, The user has already signed up!elif nn in exist_usr_info:tkinter.messagebox.showerror('Error', 'The user has already signed up!')# 最后如果输入无以上错误,则将注册输入的信息记录到文件当中,并提示注册成功Welcome!,You have successfully signed up!,然后销毁窗口。else:exist_usr_info[nn] = npwith open('usrs_info.pickle', 'wb') 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 = tk.Toplevel(window)window_sign_up.geometry('300x200')window_sign_up.title('Sign up window')new_name = tk.StringVar() # 将输入的注册名赋值给变量new_name.set('example@') # 将最初显示定为'example@'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=130, 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=130, 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=130, y=90)# 下面的 sign_to_Hongwei_Websitebtn_comfirm_sign_up = tk.Button(window_sign_up, text='Sign up', command=sign_to_Hongwei_Website)btn_comfirm_sign_up.place(x=180, y=120)# 第7步,login and sign up 按钮btn_login = tk.Button(window, text='Login', command=usr_login)btn_login.place(x=120, y=240)btn_sign_up = tk.Button(window, text='Sign up', command=usr_sign_up)btn_sign_up.place(x=200, y=240)# 第10步,主窗口循环显示window.mainloop()

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。