1.认识GUI和使用tkinter
人机交互是从人努力适应计算机,到计算机不断适应人的发展过程,大致经历了5个阶段:早期手工阶段、命令行用户接口(CLI)阶段、图形用户界面(GUI)阶段、网络用户界面阶段、智能人机交互阶段。
GUI(graphical user interface,图形用户界面)是指采用图形方式显示的用户操作界面。
大部分应用软件都属于图形用户界面(GUI)程序,如多媒体播放器、办公软件、网页浏览器等。一个完整的GUI程序实际包含两部分:组件和事件。
- 组件。图形用户界面程序一般包含很多功能组件,如窗口、菜单、按钮、文本框、复选框等。主窗口包括了所有的组件,组件自身也可以作为容器,包含其它的组件,如下拉框。组件可以分为两类:容器组件和基本组件,大部分组件都是可见的、有形的对象。
- 容器组件:可以存储基本组件和容器组件的组件。
- 基本组件:可以使用的功能组件,依赖于容器组件。
- 事件。GUI程序就是由一整套的事件所驱动的,当程序启动之后,一直监听所有组件绑定的事件。当为程序需要的每一个事件都添加回调处理函数之后,整个GUI程序就完成了。
事件就是将要发生的事情,如鼠标单击、键盘输入、页面初始化、加载完毕、移动窗口等,是图形用户交互的基础,它通过一套完整的事件监听机制实现。事件包含如下3个要素:
- 事件源:事件发生的对象,如窗口、按钮、菜单栏、文本框等。
- 事件处理器:针对可能发生的事情做出的处理方案,简单说就是事件回调函数。
- 事件监听器:把事件源和事件关联起来,如鼠标单击按钮、在文本框中输入字符等。
常用的GUI库有以下4种:
tkinter
:是TK图形用户界面工具包标准的Python接口。轻量级的跨平台图形用户界面开发工具。wxPython
:是Python对跨平台的GUI工具集wxWidgets的包装,也是比较流行的tkinter替代品。PyQt
:是Python对跨平台的GUI工具集Qt的包装。作为Python的插件,其功能非常强大,用PyQt开发的界面效果与Qt开发的界面效果相同。PySide
:是另一个Python对跨平台的GUI工具集Qt的包装,捆绑在Python中。
此外,还有一些其它的GUI库,如PyGTK、AnyGui等。
使用tkinter
创建GUI
程序需要以下5步:
- 导入
tkinter
模块。 - 创建顶层窗口。
- 构建
GUI
组件。 - 将每一个组件与底层程序代码关联起来。
- 执行主循环。
示例:
import tkinter r = tkinter.Tk() # 生成r主窗口 label = tkinter.Label(r,text='吃什么最补脑?') # 生成标签 label.pack() # 将标签添加到r主窗口 button1 = tkinter.Button(r,text='吃亏') # 生成button1 button1.pack(side=tkinter.LEFT) # 将button1添加到r主窗口,左对齐 button2 = tkinter.Button(r,text='六个核桃') # 生成button2 button2.pack(side=tkinter.RIGHT) # 将button2添加到r主窗口,右对齐 r.mainloop() # 进入消息循环,否则窗口一闪而过,看不到运行结果
2.使用组件
组件是GUI
程序开发的基础,tkinter
提供了比较丰富的组件。
Button
:按钮。类似标签,但提供额外的功能,单击时执行一个动作,如鼠标移过、按下、释放,以及键盘操作等事件。Canvas
:画布。提供绘图功能,如直线、椭圆、多边形、矩形等,可以包含图形或位图。Checkbutton
:复选按钮。允许用户勾选或取消选择,一组复选框可以成组,允许选择任意个。类似HTML中的checkbox组件。Entry
:单行文本框。显示一行文本,用来收集键盘输入。类似HTML中的text组件。Label
:标签。用于显示不可编辑的文本、图片等信息。LabelFrame
:容器控件。是一个简单的容器控件,常用于复杂的窗口布局。Listbox
:列表框。一个选项列表,用户可以从中进行选择。Menu
:菜单。单击菜单按钮后弹出的一个选项列表,用户可以从中进行选择。Menubutton
:菜单按钮。用来包含菜单的组件,有下拉式、层叠式。Message
:消息框。类似于标签,但可以显示多行文本。OptionMenu
:选择菜单。下拉菜单的改版,弥补了Listbox无法定义下拉列表框的遗憾。PanedWindow
:窗口布局管理。是一个窗口布局管理的插件,可以包含一个或者多个子控件。Radiobuttion
:单选按钮。允许用户从多个选项中选取一个,一组按钮中只有一个可被选择。类似HTML中radio组件。Scale
:滑块组件。线性‘滑块’组件,可设定起始值和结束值,显示当前位置的精确值。Scrollbar
:滚动条。对其支持的组件,如文本域、画布、列表框、文本框,提供滚动功能。Spinbox
:输入控件。与Entry类似,但是可以指定输入范围值。Text
:多行文本框。多行文本区域,显示多行文本,可以用来收集或显示用户输入的文字。类似HTML中的textarea组件。Toplevel
:顶层。容器组件,类似框架,为其它控件提供单独的容器。
messageBox
:消息框。用于显示应用程序的消息框。
2.1 标签
Label
(标签)组件用于在屏幕上显示文本或图像。仅能显示单一字体的文本,但文本可以跨越多行;另外还可以为其中的个别字符加上下画线,如用于表示键盘快捷键。
使用tkinter.Label()
构造函数可以创建标签组件,语法和示例如下:
from tkinter import * r = Tk() # 实例化,生成主窗口 r.title('使用标签组件') # 定义标签标题 label = Label(r, anchor=E, # 右侧显示 bg='#eef', # 浅灰色背景色 fg='red', # 红色字体 text='设计标签组件', #显示的文本 font=('隶书',24), # 字体类型和大小 width=20, # 标签的宽度 height=3 # 标签的高度 ) label.pack() # 调用pack方法,添加到主窗口 r.mainloop() # 进入主循环
2.2 按钮
Button
(按钮)组件用于实现各种各样的按钮。包含文本或图像,可以将一个Python函数或方法与之相关联,当按钮被按下时,对应的函数或方法将被自动执行。
Button
组件仅能显示单一字体的文本,但文本可以跨越多行,另外还可以为其中的个别字符加上下画线,用于表示键盘快捷键,默认情况下,Tab按键被用于在按钮间切换。
from tkinter import * r = Tk() r.title('使用按钮组件') Button(r,text='禁用',state=DISABLED).pack(side=RIGHT) Button(r,text='取消').pack(side=LEFT) Button(r,text='确定').pack(side=LEFT) Button(r,text='退出',command=r.quit).pack(side=RIGHT) r.mainloop()
2.3 文本框
Entry
(输入框)组件用于获取用户的输入文本,仅允许用于输入一行文本,如果用于输入的字符串长度比该组件可显示空间更长,那内容将被滚动,意味着该字符串将不能被全部看到。显示多行文本,常用于作为简单的文本编辑器和网页浏览器使用。
import tkinter as tk w = tk.Tk() w.title('读取文本框中的值') w.geometry('360x160') # 设定窗口的大小(长x宽) e = tk.Entry(w,show=None) # 显示成明文形式 e.pack() # 注意:因为Python的执行顺序是从上往下,所以函数一定要放在按钮的上面 def insert_point(): # 在鼠标焦点处插入输入内容 var = e.get() t.insert('insert',var) def insert_end(): # 在文本框内容最后接着插入输入内容 var = e.get() t.insert('end',var) # 创建并放置两个按钮分别触发两种情况 b1 = tk.Button(w,text='在光标位置插入',width=20,height=2,command=insert_point) b1.pack() b2 = tk.Button(w,text='在文本尾部位置插入',width=20,height=2,command=insert_end) b2.pack() # 创建一个多行文本框Text显示,指定3个字符高度 t = tk.Text(w,height=3) t.pack() w.mainloop()
2.4 单选按钮和复选按钮
Radiobutton
(单选按钮)组件用于实现多选一的问题,可以包含文本或图像。
Checkbutton
(复选按钮)组件用于实现确定是否选择的按钮。
import tkinter as tk w = tk.Tk() w.title('设计复选按钮') w.geometry('300x100') l = tk.Label(w,bg='yellow',width=20,text='') l.pack() def print_selection(): # 定义触发函数功能 if (var1.get()==1)&(var2.get() == 0): # 如果选中第一个选项,未选中第二个选项 l.config(text='勾选了Python') elif(var1.get()==0)&(var2.get()==1): # 如果未选中第一个选项,选中第二个选项 l.config(text='勾选了C++') elif(var1.get()==0)&(var2.get()==0): # 如果未选中第一个选项,未选中第二个选项 l.config(text='什么都没有勾选') else: # 如果两个都勾选 l.config(text='全部勾选') # 定义变量用来存放选中行为的返回值 var1 = tk.IntVar() var2 = tk.IntVar() c1 = tk.Checkbutton(w,text='Python',variable=var1,onvalue=1,offvalue=0,command=print_selection) c1.pack() c2 = tk.Checkbutton(w,text='C++',variable=var2,onvalue=1,offvalue=0,command=print_selection) c2.pack() w.mainloop()
2.5 菜单和消息
Menu
(菜单)组件用于实现顶级菜单、下拉菜单和弹出菜单。创建一个顶级菜单,需要先使用Menu()创建一个菜单实例,然后使用add()方法将命令和其它子菜单添加进去。
from tkinter import * r = Tk() r.title('设计菜单') r.geometry('300x200') m = Menu(r) filemenu = Menu(m,tearoff=0) m.add_cascade(label='文件',menu = filemenu) filemenu.add_command(label='新建') filemenu.add_command(label='打开') filemenu.add_command(label='保存') r.config(menu = m) r.mainloop()
Message
(消息)组件是Label组件的变体,用于显示多行文本消息。
from tkinter import * w = Tk() mess = '你收到一天消息' msg = Message(w,text=mess) msg.config(bg='lightgreen',font=('宋体',16,'italic')) msg.pack() w.mainloop()
2.6 列表框
Listbox
(列表框)组件用于显示一个选择列表。
''' Listbox(容器,可变关键字参数) ''' from tkinter import * r = Tk() # 创建顶级窗口 a = Label(r,bg='yellow',width=20,text='') # 定义一个提示信息显示的标签 a.pack() def f(e): # 定义选项触发功能 a.config(text='被选项为:'+l.get(l.curselection())) l =Listbox(r) # 定义列表框 l.bind('<Double-Button-1>',f) # 绑定鼠标双击事件 for i in range(10): l.insert(END,str(i)) l.pack() # 显示列表框 r.mainloop()
2.7 滚动条
Scrollbar
(滚动条)组件用于滚动一些组件的可见范围,根据方向可分为垂直滚动条和水平滚动条。
from tkinter import * r = Tk() sb = Scrollbar(r,orient=HORIZONTAL) # 滚动条水平显示,不写默认垂直滚动 sb.set(0.5,1) # 设置滑块的位置 sb.pack() # 显示滚动条 r.mainloop()
2.8 框架
Frame
组件主要用于在复杂的布局中将其他组件分组,也用于填充间距和作为实现组件的基类。
from tkinter import * r = Tk() # 创建顶级窗口 r.title('设计框架') r.geometry('600x500') fm = Frame(height=200,width=200,bg='green',border=2) fm.pack_propagate(0) # 固定frame大小,如果不设置,frame随着标签大小改变 fm.pack() # 显示框架 Label(fm,text='左侧标签').pack(side='left') Label(fm,text='右侧标签').pack(side='right') r.mainloop()
2.9 画布
Canvas
是一个通用的组件,通常用于显示和编辑图形,可以用它绘制线段、圆形、多边形、甚至绘制其它组件。
from tkinter import * r = Tk() r.title('使用画布') w = Canvas(r,width=200,height=100) # 创建画布 w.pack() # 显示画布 w.create_line(0,50,200,50,fill='yellow') # 画一条黄色的横线 w.create_line(100,0,100,100,fill='red',dash=(4,4)) # 画一条红色的竖线(虚线) w.create_rectangle(50,25,150,75,fill='blue') # 中间画一个蓝色的矩形 Button(r,text='删除全部',command=(lambda x='all':w.delete(x))).pack() r.mainloop()
3. 组件布局
tkinter 提供了3个布局管理器:pack(包),按添加顺序排列组件;grid(网格),按行、列格式排列组件;place(位置),准确设置组件的大小和位置。
**grid 布局:**可以以网络化设置组件的位置,但不要在同一父组件中混合使用pack和grid。
from tkinter import * r = Tk() r.title('问卷调查') Label(r,text='姓名').grid(row=0) Label(r,text='密码').grid(row=1) Label(r,text='兴趣爱好').grid(row=2) Entry(r).grid(row=0,column=1) Entry(r).grid(row=1,column=1) Entry(r).grid(row=2,column=1) r.mainloop()
place 布局:可以精确定义组件的位置和大小
from tkinter import * r = Tk() r.title('小样') def callback(): print('正中靶心') tk.Button(r,text='打我',command=callback).place(relx=0.5,rely=0.5,anchor='center') r.mainloop()
4.事件处理
事件序列是以字符串的形式表示一个或多个相关联的事件。它包含在<>中。
''' <modifier-type-detail> type:用于描述通用事件类型,如鼠标单击、键盘按键单击等。 modifier:可选项,用于描述组合键,如Ctrl+C表示同时按Ctrl和C键。 detail:可选项,用于描述具体的按键,如Button-1表示鼠标左键。 ''' <Button-1> # 用户单击鼠标左键 <KeyPress-H> # 用户单击H按键 <Control-Shift-KeyPress-H> # 用户同时按Ctrl+Shift+H组合键
事件绑定有4种方法:
1、创建组件对象时指定。通过参数command指定。
b = Button(root,text=‘按钮’,command=clickhandler)
2、实例绑定。调用组件对象的bind()方法,可以为指定组件绑定事件。
w.bind(‘’,eventhandler,add=‘’)
3、类绑定。调用组件对象的bind_class()方法,为特定类绑定事件。
w.bind(‘Widget’,‘’,eventhandler,add=‘’)
4、程序界面绑定。调用组件对象的bind_all()方法,为所有组件类型绑定事件。
w.bind_all(‘’,eventhandler,add=‘’)
import tkinter as tk r = tk.Tk() entry = tk.Entry(r) def f1(event): event.widget['bg'] = 'red' def f2(event): event.widget['bg'] = 'white' entry.bind('<Enter>',f1) # 鼠标经过时,背景色显示红色 entry.bind('<Leave>',f2) # 鼠标离开时,背景色显示白色 entry.pack() r.mainloop()
事件对象:通过传入的事件对象,可以访问该对象属性,获取事件发生时相关参数,以备程序使用。
- widget:事件源,即产生该事件的组件。
- x,y:当前鼠标指针的坐标位置(相对于窗口左上角,以像素为单位)。
- x_root,y_root:当前鼠标指针的坐标位置(相对于屏幕左上角,以像素为单位)。
- keysym:按键名。
- keycode:按键码。
- num:按钮数字(鼠标事件专属)。
- width, height:组件的新尺寸(Configure事件专属)。
import tkinter as tk r = tk.Tk() def callback(event): # 事件处理函数,参数event为Event事件对象 print('点击的键盘字符为:',event.char) fm = tk.Frame(r,width=200,height=200) fm.bind('<Key>',callback) # 绑定鼠标单击事件 fm.focus_set() # 获取焦点,接收键盘响应 fm.pack() r.mainloop()