一、图形界面编程
图形用户界面(Graphical User Interface,GUI)是用户与程序交互的接口,好的GUI会大大提高用户交互体验,其实就是我们平时使用电脑时,使用鼠标、键盘点击的程序界面。
Python提供很多创建GUI的程序库,程序员可以选择其中的一个来创建自己的程序界面。
- PyGObject: 基于GObject的C函数库提供了内省绑定,这些库支持GTK+3图形界面工具集,因此PyGObject提供了丰富的图形界面组件。
- PyGTK:基于老版GTK+2的库(C语言)提供绑定,官方网站。
- PyQt:Python编程语言和Qt库(C++GUI应用开放框架)的融合,可跨平台使用
- PySide:Nokia提供的Qt封装,
- wxPython:以wxWidgets为基础,在不同平台调用不同的本都组件,以符合平台风格。跨平台GUI库,官方网站。
如果读者需要,可以选择任意的GUI库来开发图形界面。如果考虑开发跨平台界面,推荐使用PyQt或wxPython。
本章介绍的GUI库时Tkinter,它是Python自带的GUI库,无需额外下载安装,只要导入tkinter包即可使用。
与其他编程语言的 GUI 工具包相比,Tkinter 编码效率高,能够实现快速开发的目的,非常适合初学者学习。Tkinter 使用纯 Python 语言开发,与 C/C++ 开发的 Qt 框架相比,Tkinter 有自身的局限性,比如性能、功能丰富程度等都不及 Qt,因此它只适合开发一些简单的程序,比如计算器的界面,或者一个简易的聊天窗口等。
学习GUI编程类似于搭建积木的过程,我们也通过这个步骤来讲解:
- 了解我们这套积木中都含有哪些积木块(GUI库中包含的组件),都是个什么东西。
- 准备一张桌子来作为工作场地(建立程序主窗口)
- 将积木拼接在一起(在容器/窗口中对组件布局)
- 深入掌握每个积木块的功能和用法(各组件用法,完成工作内容)
接下来我们将一步一步实现界面编程。
1.1 Tkinter GUI编程组件
其实,Tkinter是一个程序包,里面包含了很多模块,例如Tk、ttk、messagebox等,Tk模块是创建简单界面的主要模块,其中的组件也是继承了object类,下图显示了各组件的继承关系:
现在我们来了解一下‘积木块’的大体功能,不求完全记住,后面还会有详细讲解。
下表列出了 Tkinter 中常用的 15 个组件:
组件类型 | 组件名称 | 组件作用 |
---|---|---|
Button | 按钮 | 点击按钮时触发/执行一些事件(函数) |
Canvas | 画布 | 提供绘制图,比如直线、矩形、多边形等 |
Checkbutton | 复选框 | 多项选择按钮,用于在程序中提供多项选择框 |
Entry | 文本框输入框 | 用于接收单行文本输入 |
Frame | 框架(容器)控件 | 定义一个窗体(根窗口也是一个窗体),用于承载其他控件,即作为其他控件的容器 |
Lable | 标签控件 | 用于显示单行文本或者图片 |
LableFrame | 容器控件 | 一个简单的容器控件,常用于复杂的窗口布局。 |
Listbox | 列表框控件 | 以列表的形式显示文本 |
Menu | 菜单控件 | 菜单组件(下拉菜单和弹出菜单) |
Menubutton | 菜单按钮控件 用于显示菜单项 | |
Message | 信息控件 | 用于显示多行不可编辑的文本,与 Label控件类似,增加了自动分行的功能 |
messageBox | 消息框控件 | 定义与用户交互的消息对话框 |
OptionMenu | 选项菜单 | 下拉菜单 |
PanedWindow | 窗口布局管理组件 | 为组件提供一个框架,允许用户自己划分窗口空间 |
Radiobutton | 单选框 | 单项选择按钮,只允许从多个选项中选择一项 |
Scale | 进度条控件 | 定义一个线性“滑块”用来控制范围,可以设定起始值和结束值,并显示当前位置的精确值 |
Spinbox | 高级输入框 | Entry 控件的升级版,可以通过该组件的上、下箭头选择不同的值 |
Scrollbar | 滚动条 | 默认垂直方向,鼠标拖动改变数值,可以和 Text、Listbox、Canvas等控件配合使用 |
Text | 多行文本框 | 接收或输出多行文本内容 |
Toplevel | 子窗口 | 在创建一个独立于主窗口之外的子窗口,位于主窗口的上一层,可作为其他控件的容器 |
在后续内容中,我们会陆续对上表中涉及的组件(也有称为控件的)进行介绍。当然,除了上述组件外,还有一些高级组件,比如 PanedWindow、messagebox、LableFrame、Spinbox,在后续章节也会讲解。
从上表来看,每个组件都有着各自不同的功能,即使有些组件功能相似,但它们的适用场景也不同。
在 Tkinter 中不同的组件受到各自参数的约束(即参数),所有组件既有相同属性,也有各自独有的属性。本节内容,先对这些组件的共用属性做简单介绍,如下表所示:
属性名称 | 说明 | 单位 | 典型值 |
---|---|---|---|
background(bg) | 背景颜色,参数值可以颜色的十六进制数,或者颜色英文单词 | COLOR | ‘gray25’或‘#ff4400’ |
foreground(fg) | 前景色,也就是字体的颜色,参数值可以颜色的十六进制数,或者颜色英文单词 | COLOR | ‘gray25’或‘#ff4400’ |
activebackground | 激活状态时的背景色 | color | ‘gray25’或‘#ff4400’ |
activeforeground | 激活状态时的前景色 | color | ‘gray25’或‘#ff4400’ |
highlightbackground | 高亮状态时的背景色 | color | ‘gray25’或‘#ff4400’ |
highlightcolor | 高亮状态时的前景色 | color | ‘gray25’或‘#ff4400’ |
selectbackground | 选中状态时的背景色 | color | ‘gray25’或‘#ff4400’ |
selecforeground | 选中状态时的前景色 | color | ‘gray25’或‘#ff4400’ |
disabledforground | 禁止状态时的前景色 | color | ‘gray25’或‘#ff4400’ |
height | 该参数值用来设置组件的高度,文本控件以字符的高度(px,font指定),其他控件则以像素为单位 | px或pixel | 14 |
width | 用于设置控件的宽度,文本控件以字符的高度(px,font指定),其他控件则以像素为单位 | px或pixel | 14 |
borderwidth | 定于组件的边框宽度 | pixel | 2 |
highlightthickness | 高亮状态下周围方形区域宽度 | pixel | 2 |
selectborderwidth | 选中状态时的边框宽度 | pixel | 2 |
relief | 定义组件的边框样式 | constant | FLAT(平的)/RAISED(凸起的)/SUNKEN(凹陷的)/GROOVE(沟槽桩边缘)/RIDGE(脊状边缘) |
image | 定义显示在组件内的图片文件 | address | |
bitmap | 定义显示在组件内的位图文件,受anchor、justify选项影响,同时指定bitmap、text、image时,可能会覆盖低优先级的选项,优先级关系为image>bitmap>text | address | |
text | 定义控件的标题文字 | str | ‘确定’ |
testcariable | 指定显示文本的变量 | variable | bnText |
font | 若组件支持设置标题文字,就可以使用此属性来定义,它是一个数组格式的参数 (字体,大小,字体样式) | 数组 | ‘Helvetica’或(‘Verdana’,8) |
anchor | 定义组件信息(文本或图片)在窗口内的位置 | N(上)、NE(左上角)、E(右)、SE、S、SW、W、NW、CENTER | |
justify | 定义多行文字的对齐方式 | constant | LEFT/CENTER/RIGHT |
padx/pady | 定义组件内的文字或者图片与控件边框之间的水平/垂直距离 | pixel | 12 |
state | 控制组件是否处于可用状态 | constant | 参数值默认为 NORMAL/DISABLED,默认为 NORMAL(正常的) |
takefocus | 组件在键盘遍历(Tab或Shift+Tab)时,是否接收焦点 | boolean | 1或Yes(接受);0或No(不接收) |
command | 执行事件函数,比如单击按钮时执行特定的动作,可将执行用户自定义的函数 | ||
cursor | 当鼠标指针移动到组件上时,定义鼠标指针的类型 | cursor | crosshair(十字光标)、watch(待加载圆圈)、plus(加号)、arrow(箭头)、gumby等 |
注意:对于上述属性先做大体的了解即可,因为后续章节会对这些控件做更为详细的介绍。 |
1.2 建立主窗口Tk
主窗口(Tk对象)是一切组件的基础,它好比是一台高速运转的机器,而其他控件则相当于这台机器上的部件,比如齿轮、链条、螺丝等等。由此我们知道,主窗口是一切控件的基础,所有的控件的都需要通过主窗口来显示。
Tkinter 能够很方便地创建一个空白窗口,值得注意的是Python 2.x需要import Tkinter,Python 3.x需要import tkinter。
创建窗口对象可以使用2中方法,
- 使用Tk()类创建窗口(此时里面什么都没有,指定了自命名的master主窗口)
- 直接创建组件的子类,可以默认初始化一个含有该组件的窗口(使用self.master引用),不建议这么使用。
1.2.1 使用Tk()创建窗口
示例代码如下:
# 导入tk
from tkinter import *
# 创建一个主窗口对象
window = Tk()
# 调用mainloop()显示主窗口
window.mainloop()
程序运行结果如下:
- 窗口常用方法
下表列出了窗口的常用方法,其中 window 代表主窗口对象:
函数 | 说明 |
---|---|
window.title(“my title”) | 接受一个字符串参数,为窗口起一个标题 |
window.resizable() | 是否允许用户拉伸主窗口大小,默认为可更改,当设置为 resizable(0,0)或者resizable(False,False)时不可更改 |
window.geometry() | 设定主窗口的大小以及位置,当参数值为 None 时表示获取窗口的大小和位置信息。 |
window.quit() | 关闭当前窗口 |
window.update() | 刷新当前窗口 |
window.mainloop() | 设置窗口主循环,使窗口循环显示(一直显示,指导窗口被关闭) |
window.iconbitmap() | 设置窗口左上角的图标(图标是.ico文件类型) |
window.config(background =“red”) | 设置窗口的背景色为红色,也可以接受 16 进制的颜色值 |
window.minsize(50,50) | 设置窗口被允许调整的最小范围,即宽和高各50 |
window.maxsize(400,400) | 设置窗口被允许调整的最大范围,即宽和高各400 |
window.attributes(“-alpha”,0.5) | 用来设置窗口的一些属性,比如透明度(-alpha)、是否置顶(-topmost)即将主屏置于其他图标之上、是否全屏(-fullscreen)全屏显示等 |
window.state(“normal”) | 用来设置窗口的显示状态,参数值 normal(正常显示),icon(最小化),zoomed(最大化) |
window.withdraw() | 用来隐藏主窗口,但不会销毁窗口。 |
window.iconify() | 设置窗口最小化 |
window.deiconify() | 将窗口从隐藏状态还原 |
window.winfo_screenwidth() | 获取电脑屏幕的分辨率(尺寸) |
window.winfo_screenheight() | 获取电脑屏幕的分辨率(尺寸) |
window.winfo_width() | |
window.winfo_height() | 获取窗口的大小,同样也适用于其他控件,但是使用前需要使用 window.update() 刷新屏幕,否则返回值为1 |
window.protocol(“协议名”,回调函数) | 启用协议处理机制,常用协议有 WN_DELETE_WINDOW,当用户点击关闭窗口时,窗口不会关闭,而是触发回调函数。 |
下面通一个示例对上述表格中的常用方法做简单地介绍:
import tkinter as tk
window =tk.Tk()
#设置窗口title
window.title('Python学习')
#设置窗口大小:宽x高,注,此处不能为 "*",必须使用 "x"
window.geometry('450x300')
# 获取电脑屏幕的大小
print("电脑的分辨率是%dx%d"%(window.winfo_screenwidth(),window.winfo_screenheight()))
# 要求窗口的大小,必须先刷新一下屏幕
window.update()
print("窗口的分辨率是%dx%d"%(window.winfo_width(),window.winfo_height()))
# 如使用该函数则窗口不能被拉伸
# window.resizable(0,0)
# 改变背景颜色
window.config(background="#6fb765")
# 设置窗口处于顶层
window.attributes('-topmost',True)
# 设置窗口的透明度
window.attributes('-alpha',1)
# 设置窗口被允许最大调整的范围,与resizble()冲突
window.maxsize(600,600)
# 设置窗口被允许最小调整的范围,与resizble()冲突
window.minsize(50,50)
#更改左上角窗口的的icon图标,加载C语言中文网logo标
window.iconbitmap('C:/Users/Administrator/Desktop/favicon.ico')
#添加文本内容,并对字体添加相应的格式 font(字体,字号,"字体类型")
text=tk.Label(window,text="Python学习,网址:https://editor.csdn.net",bg="yellow",fg="red",font=('Times', 15, 'bold italic underline'))
#将文本内容放置在主窗口内
text.pack()
# 添加按钮,以及按钮的文本,并通过command 参数设置关闭窗口的功能
button=tk.Button(window,text="关闭",command=window.quit)
# 将按钮放置在主窗口内
button.pack(side="bottom")
#进入主循环,显示主窗口
window.mainloop()
- protocol协议处理机制
Tkinter 除了提供事件绑定机制之外,还提供了协议处理机制,它指的是应用程序和窗口管理器之间的交互,最常用的协议为 WM_DELETE_WINDOW。
当 Tkinter 使用 WM_DELETE_WINDOW 协议与主窗口进行交互时,Tkinter 主窗口右上角x号的关闭功能失效,也就是无法通过点击x来关闭窗口,而是转变成调用用户自定义的函数。
下面看一组简单的示例:
from tkinter import Tk
# 导入 对话框控件
from tkinter import messagebox
# 创建主窗口
root = Tk()
# 定义回调函数,当用户点击窗口x退出时,执行用户自定义的函数
def QueryWindow():
# 显示一个警告信息,点击确后,销毁窗口
if messagebox.showwarning("警告","出现了一个错误"):
# 这里必须使用 destory()关闭窗口
root.destroy()
# 使用协议机制与窗口交互,并回调用户自定义的函数
root.protocol('WM_DELETE_WINDOW', QueryWindow)
root.mainloop()
通过封装函数的形式来执行相应的 GUI 控件功能,这在学习 Tkinter 编程的整个过程中非常常见,比如 Button 控件的command参数也可以执行回调函数,如下所示:
import tkinter as tk
# 定义窗口
window = tk.Tk()
window.title('Python学习')
window.geometry('300x300')
window.iconbitmap('C:/Users/Administrator/Desktop/favicon.ico')
# 定义回调函数
def callback():
print("执行回调函数","欢迎学习Python")
# 点击执行按钮
button = tk.Button(window, text="执行", command=callback)
button.pack()
window.mainloop()
设置窗口位置
当我们运行 Tkinter 程序时,主窗口都会出现在距离屏幕左上角指定的位置上,这是由 Tkinter 软件包默认设置的。但是在许多情况下,我们需要根据实际情况来移动窗口在电脑屏幕上的位置,这时应该如何处理呢?其实很简单,通过窗口对象的 geometry() 方法即可改变主窗口的位置,其语法格式如下:
geometry('450x400+300+200')
上述代码表示,设置主窗口的宽度为 450,高度为 400,同时窗口距离左边屏幕的距离为 300(以像素为单位),距离屏幕顶部的距离为 200,这里我们将带“+”的参数值称为“位置参数”,当然,您也可以将它们设置为负数,如下所示:
geometry('+-1500+-2000')
当设置了一个超过屏幕的负参数值时,主窗口会被移动至“屏幕之外”,此时就看不到主窗口了,这也是隐藏窗口的一种方法。
下面看一组简单的示例:
import tkinter as tk
window = tk.Tk()
window.title('Python学习')
window.iconbitmap('C:/Users/Administrator/Desktop/favicon.ico')
# 设置窗口大小变量
width = 300
height = 300
# 窗口居中,获取屏幕尺寸以计算布局参数,使窗口居屏幕中央
screenwidth = window.winfo_screenwidth()
screenheight = window.winfo_screenheight()
size_geo = '%dx%d+%d+%d' % (width, height, (screenwidth-width)/2, (screenheight-height)/2)
window.geometry(size_geo)
window.mainloop()
程序运行后窗口将出现在屏幕的中间位置。
1.2.2 使用组件创建窗口
上一小节我们使用TK()创建了主窗口,然后在Windows主窗口上面创建组件的方式来构建我们的用户接口。还有一种方式就是字节创建组件的子类,子类就会自动创建TK对象作为窗口,例如下面的程序(以Frame为例)
from thinter import *
#定义继承Frame的Application类
class Application(Frame):
def __init__(self,master=None):
Frame.__init__(self,master)
self.pack()
# 调用initWidgets()方法初始化界面
self.initWidgets()
def initWidgets(self):
#创建Lable对象,第一个参数指定将该Lable放入本类(self)中
w = Lable(self)
#创建一个位图
bm = PhotoImage(file = 'serial.png')
#使用一个变量引用图片,避免图片变量无引用时被自动回收
w.x = bm
#设置Lable显示图片
w['image'] = bm
#放入窗口中
w.pack()
# 创建Button对象
okButton = Button(self,text='确定‘)
okButton['background'] = 'yellow'
# okButton.co