人生苦短,快学Python!
图形用户界面(GUI)是为用户交互提供灵活性的界面,很多小伙伴都希望把自己的Python小程序都加上一个可视化界面。即美观,又有交互性。常见的Python必备的GUI库有:Tkinter、PyQt5、Kivy、wxPython、PySimpleGUI等等。后续这些有用有趣的模块在快学Python都会陆续介绍的。
本篇文章将先结合实际案例,来介绍Tkinter
的主要功能。
在案例开始之前,我们需要先认识一下 —— Tkinter。
一、Tkinter初识
Tkinter,GUI编程的一个第三方库。是最受欢迎的软件包之一,它允许您使用 Python 构建 GUI!
而 GUI 即 graphicaluser interface,即图形界面用户接口,是相对于绝大多数编程语言所接触到的“控制台”的那个黑乎乎的命令行所区分的编程模式,Tkinter 是 Tk 的 Python 接口。
Tkinter 的优点和缺点
- 简单易学,相对于其他的比如 PyGtk,PyQt 等等,比较简单;
- 可以使用少量的代码产生功能强大的 GUI 界面,这一点是相对于 C 等语言来说的,这也是绝大多数脚本语言令人自豪的地方;
- 跨平台;
- 内置于Python 里面的,不需要我们单独去安装,是方便了很多,也是一个 Python 里面的标准;
- 缺点就是功能过于简单,使用tkinter这个框架提供的功能还是太少了,很多功能还是需要手动实现;
- 还有一个缺点是相对于 C 来说的,它的效率问题还是不算太高,对于一些对画面要求很高的。
二、第一个 tkinter 程序
起步
代码语言:javascript复制import tkinter # 导入tkinter模块
tkinter._test() # 测试tkinter包是否好用
运行结果如下:
在这里点击quit按钮不会退出,只有点击X号才会退出程序。
第一个程序
代码语言:javascript复制import tkinter
base = tkinter.Tk() # Tk 这个类进行实例化,即 base 是它的一个实例
base.wm_title('Tk Test') # 设置标题
base.mainloop() # 进行事件循环
运行结果:
三、认识组件
如果大家习惯了 windows 编程,那么对于“控件”一次一定不会陌生,其实呢,组件和控件是一回事,在本书中我们不加以区分。
组件--Label
组件的英文表述是“widget”,我们常见的按钮,文本框等等都可以当做组件。我们可以为一个窗口增加若干组件来丰富该窗口的功能,我们往往需要指定这个组件的大小和位置,我们还需要通过编程的方式来指定该组件能完成什么功能。
Label标签
下面是代码示例:
代码语言:javascript复制import tkinter
base = tkinter.Tk() # 实例化
base.wm_title('Tk Test')
w1 = tkinter.Label(base,text='Python Label') # 创建一个label标签,放在base上
w1.pack()
base.mainloop()
运行结果:
代码解释:
1.这里的 Label 是一个类, 可以在__init__.py 文件里查看相应的源代码。 2.w1 是一个 Label 的实例, 它有一个 text 属性, 用来指定它的文本内容。 3.w1.pack() 表示布局,指定了摆放位置(后面会有详细提及)
- 多标签的应用程序
针对于多个标签的实例, 先声明,然后分别 pack 到窗口上即可。
下面是代码示例:
代码语言:javascript复制from tkinter import *
root = Tk()
root.wm_title('组件')
w1 = Label(root,text='阿莱斯基的闪电',background='green')
w2 = Label(root,text='阿莱斯基的闪电',background='blue')
w3 = Label(root,text='阿莱斯基的闪电',background='yellow')
w1.pack()
w2.pack()
w3.pack()
root.mainloop()
运行结果:
组件--Button
按钮与功能的绑定
在按钮组件被声明的时候用 command 属性声明,command 属性接受一个函数名,注意函数名不要加双引号。
代码语言:javascript复制我们要完成的功能是我们按下这个按钮的时候,就会在窗口上增加一个背景颜色随机的 Label,它显示“我爱 python”。
from tkinter import *
import random
color = ['red','orange','yellow','green','blue','purple','black']
def xinLovePython():
global root
b1 = Label(root,text='I like Python',background=random.choice(color))
b1.pack()
root = Tk()
btn = Button(root,tetx = '九黎',command = xinLovePython)
btn.pack()
root.mainloop()
运行结果:
输入框
为了获取用户信息,很明显一直点击按钮不太合适,于是输入框出现了。
Entry(输入框)
- 部分源代码截图:
class Entry(Widget, XView):
def __init__(self, master=None, cnf={}, **kw):
Widget.__init__(self, master, 'entry', cnf, kw)
def get(self):
"""Return the text."""
return self.tk.call(self._w, 'get')
- 源码中比较重要的函数是get 函数,get 函数使用的时候不需要任何参数,它的返回值就是该输入框的内容。
密码框
- 其实密码框和输入框基本是一样的,都是向里面输入信息用的;
- 如果要说不一样, 也就一个地方不一样:密码框需要输入的信息的显示字符比较单一;
- 比如 e 是一个输入框,我们可以设置它的 show 属性让它变成一个密码框, 即 e[‘show’] = ‘*’就可以了。
代码示例:
代码语言:javascript复制from tkinter import *
def login():
s1 = e1.get()
s2 = e2.get()
t1= len(s1)
t2 = len(s2)
if s1 == 'yyds' and s2 == 'jiuli':
c['text'] = '登录成功'
root = Tk() # 主界面
l = Label(root,text='用户名:') # 用户名的label
l.grid(row=0,column=0,sticky=W)
e1 = Entry(root)
e1.grid(row=0,column=1,sticky=E)
l2 = Label(root,text='密码:') # 密码的label
l2.grid(row=1,column=0,sticky=W)
e2 = Entry(root)
e2['show'] = '*'
e2.grid(row=1,column=1,sticky=E)
b = Button(root,text='登录',command=login)
b.grid(row=2,column=1,sticky=E)
c = Label(root,text='')
c.grid(row=3)
root.mainloop()
结果如下:
四、tkinter 的布局
常见的有三种布局方式:
pack布局
pack()
布局非常简单, 我们不用做过多的设置, 直接使用一个pack 函数就可以了。
示例如下:
代码语言:javascript复制from tkinter import *
baseFrame = Tk()
btn1 = Button(baseFrame,text='A',background='red').pack(side=LEFT,expand=YES,fill=Y)
btn2 = Button(baseFrame,text='B',background='blue').pack(side=TOP,expand=YES,fill=BOTH)
btn3 = Button(baseFrame,text='C',background='orange').pack(side=RIGHT,expand=YES,fill=None,anchor=NE)
btn4 = Button(baseFrame,text='D',background='yellow').pack(side=LEFT,expand=NO,fill=Y)
btn5 = Button(baseFrame,text='E',background='green').pack(side=TOP,expand=NO,fill=BOTH)
btn6 = Button(baseFrame,text='F',background='purple').pack(side=BOTTOM,expand=YES)
btn7 = Button(baseFrame,text='G',background='red').pack(anchor=SE)
baseFrame.mainloop()
运行结果:
解释:
我们使用 pack 函数的时候,默认先使用的放到上面,然后 依次向下排,它会给我们的组件一个自认为合适的位置和大小,这是默认方式,也是我们上面一直采用的方式。
pack 函数也可以接受几个参数:
- side 参数指定了它停靠在哪个方向,可以为 LEFT,TOP,RIGHT,BOTTOM,分别代表左、上、右、下;
- 它的 fill 参数可以是 X,Y,BOTH 和 NONE,即在水平方向填充、竖直方向填充、水平和竖直方向填充和不填充;
- 它的 expand 参数可以是 YES 和 NO,它的 anchor 参数可以是 N,E,S,W(这里的 NESW 分别表示北东南西,这里分别 表示上右下左)以及他们的组合或者是 CENTER(表示中间);
- 它的 ipadx 表示的是内边距的 x 方向,它的 ipady 表示的是内边距的 y 方向;
- padx 表示的是外边距的 x 方向,pady 表示的是外边距的 y 方向;
grid布局
grid
可以理解为网格,或者表格,它可以把界面设置为几行几列的网格,我们在网格里插入我们想要的元素。
这种布局的好处是不管我们如何拖动窗口,相对位置是不会变化的,而且这种布局也超简单。
示例如下:
代码语言:javascript复制from tkinter import *
xin = Tk()
# Entry 表示“输入框”。
Label(xin,text='账号:').grid(row=0,sticky= W)
Entry(xin).grid(row=0,column=1,sticky=E)
Label(xin,text='密码:').grid(row=1,sticky=W)
Entry(xin).grid(row=1,column=1,sticky=E)
Button(xin,text='登录:').grid(row=2,column=1,sticky=W)
xin.mainloop()
运行结果:
place布局
关于 place 布局,使用场景比较少;
它使用 place 函数,它分为绝对布局和相对布局、绝对布局使用 x 和 y 参数,相对布局使用 relx、rely,relheight 和 relwidth 参数。
五、事件
首先,什么是事件?
什么是事件?
- 事件的英文表述是“event”, 绝大多数界面编程也都会涉及到“事件”;
- 用户的很多操作,比如我们点击了一下鼠标, 这就是一个事件, 而操作系统会根据我们的相应的事件产生相应的 消息, 操作系统把消息传递给我们的应用程序, 然后我们的应用程序根据操作系统传入的数据执行相应的命令;
- 事件是用户触发的, 消息是操作系统根据而事件产生。
事件及其绑定
- 其实, 我们在按钮那一节就接触到了事件的绑定, 使用的函数是 bind;
- bind 函数的调用规则:窗体对象.bind(事件类型,回调函数);
- 所谓的“回调函数”, 就是这个函数我们不用去调用它, 当相应的事件发生的时候, 它会自动取调用。比如当我们 的按钮被按下的时候, 它会被自动调用。
常用的事件
<Button-1>
表示鼠标左键单击,其中的 1 换成 3 表示右键被单击, 为 2 的时候表示鼠标中键, 感觉不算常用;<KeyPress-A>
表示 A 键被按下, 其中的 A 可以换成其他的键位;<Control-V>
表示按下的是 Ctrl 和 V 键, V 可以换成其他键位;<F1>
表示按下的是 F1 键, 对于 Fn 系列的, 都可以随便换。
绑定
- 事件不仅可以与 Button 绑定, 我们之前看过源代码, 发现 bind 函数是定义在 Misc 类里面的, 也就是说这个bind 可以被绝大多数组件类所使用;
- 我们可以让“标签”来模拟“按钮”的作用;
- 因为标签是 Label 类, 而 Label 类继承自 Widget, 而Widget 继承自 BaseWidget, 而 Basewidget 继承自 Misc;
- 其实不仅是标签可以模拟 button, 任何组件都可以模拟它, 只是那么有用。
标签模拟按钮
代码语言:javascript复制from tkinter import *
root = Tk()
def Monibtn(event):
global root
mbtn = Label(root,text='测试')
mbtn.pack()
l = Label(root,text='模拟按钮')
l.bind('<Button-1>',Monibtn)
l.pack()
root.mainloop()
如图所示:
bind 函数
关于 bind 函数,还有两种用法:
bind_all
: 全程序级别的绑定, 它的参数类型和 bind 一样, 它通常用于全局的快捷键, 比如 F1 通常是用来打开帮助文档。
bind_class
:绑定某些类别, 它接受三个参数, 第一个参数是类名, 第二个参数是事件类型, 第三个参数是相应的操作。
比如 w.bind_class(“Entry”,“<Control-V>”,my_paste)
, 它就是绑定了所有的所有的输入框的 Ctrl V 表示粘贴。
解除绑定
接触绑定我们使用 unbind 方法,它和 bind 的使用很相似;
不过 unbind 方法只需要一个参数就可以了, 它只需要解除绑定的事件类型, 因为它会解除该绑定事件类型的所有回调函数。
六、在线简单翻译程序
最后,我们使用一个案例(在线简单翻译程序),来实战一下Tkinter
制作图形用户界面!
具体预期实现效果如下所示:
我们希望通过用户输入查询词,并获取然后向百度翻译发起请求得到结果,填充到结果框。
核心代码
数据请求
代码语言:javascript复制def translate_word(string):
url = "https://fanyi.baidu.com/sug" # 请求数据的url链接
data = {
'kw':string,
}
data_url = urllib.parse.urlencode(data)
req = urllib.request.Request(url=url,data=data_url.encode('utf-8'))
response = urllib.request.urlopen(req).read()
res = json.loads(response)
return res['data'][0]['v'].split(';')[0]
使用urllib的方法去进行数据请求,得到json数据,转化为字典,由于翻译结果是有键值对,我们提取结果即可。
界面
代码语言:javascript复制root = Tk()
root.title('小小翻译器')
root['width'] = 250;root['height'] = 130
Label(root,text='请输入要翻译的内容:',width=15).place(x=1,y=1)
Entry1 = Entry(root,width=20)
Entry1.place(x=110,y=1)
Label(root,text='翻译结果:',width=18).place(x=1,y=20)
s = StringVar()
s.set('')
Entry2 = Entry(root,width=20,textvariable=s)
Entry2.place(x=110,y=20)
Button1 = Button(root,text='翻译',width=8)
Button1.place(x=40,y=80)
Button2 = Button(root, text='清空', width=8)
Button2.place(x=130, y=80)
Button1.bind("<Button-1>",leftClick) # 事件绑定
Button2.bind("<Button-1>",leftClick2) # 事件绑定
如下所示:
函数绑定
翻译按钮
函数绑定:
def leftClick(evvnt):
enstr = Entry1.get() # 获得翻译词的内容
vText = translate_word(enstr) # 翻译函数得到翻译结果
Entry2.config(Entry2,text=vText) # 翻译结果填充到第二个输入框
s.set('')
Entry2.insert(0,vText)
清空按钮
函数绑定:
def leftClick2():
s.set('')
Entry2.insert(0,'') # 清空译文内容
七、小结
Tkinter
模块("Tk 接口")是Python的标准 Tk GUI工具包的接口。
Tkinter提供了大量组件进行图形界面开发,以创建功能复杂的界面程序,跨平台的特点是Tkinter的优势之一,可以在大多数的Unix平台下使用,同样可以应用在Windows和Macintosh系统里,通过与爬虫程序的结合,打造简单的GUI界面应用程序。
在后续的文章中,我们将继续介绍PyQt5、wxPython、PySimpleGUI等GUI库的使用方法!
人生苦短,快学Python