python程序交互界面之GUI窗体程序 Tkinter
关于Tkinter
Tkinter 模块(Tk 接口)是 Python 的标准 Tk GUI 工具包的接口 .Tk 和 Tkinter 可以在大多数的 Unix 平台下使用,同样可以应用在 Windows 和 Macintosh 系统里。Tk8.0 的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中。
Tkinter模块("Tk 接口")是Python的标准Tk GUI工具包的接口。作为 python 特定的GUI界面,是一个图像的窗口,tkinter是python 自带的,可以编辑的GUI界面,我们可以用GUI 实现很多直观的功能,比如想开发一个计算器,如果只是一个程序输入,输出窗口的话,是没用用户体验的。所有开发一个图像化的小窗口,就是必要的。
对于稍有GUI编程经验的人来说,Python的Tkinter界面库是非常简单的。python的GUI库非常多,选择Tkinter,一是最为简单,二是自带库,不需下载安装,随时使用,三则是从需求出发,Python作为一种脚本语言,一种胶水语言,一般不会用它来开发复杂的桌面应用,它并不具备这方面的优势,使用Python,可以把它作为一个灵活的工具,而不是作为主要开发语言,那么在工作中,需要制作一个小工具,肯定是需要有界面的,不仅自己用,也能分享别人使用,在这种需求下,Tkinter是足够胜任的!
Tkinter 编程
Tkinter 是 Python 的标准 GUI 库。Python 使用 Tkinter 可以快速的创建 GUI 应用程序。
由于 Tkinter 是内置到 python 的安装包中、只要安装好 Python 之后就能 import Tkinter 库、而且 IDLE 也是用 Tkinter 编写而成、对于简单的图形界面 Tkinter 还是能应付自如。
import tkinter
Tkinter 组件
Tkinter的提供各种控件,如按钮,标签和文本框,一个GUI应用程序中使用。这些控件通常被称为控件或者部件。
目前有15种Tkinter的部件。我们提出这些部件以及一个简短的介绍,在下面的表:
控件 | 描述 |
---|---|
Button | 按钮控件;在程序中显示按钮。 |
Canvas | 画布控件;显示图形元素如线条或文本 |
Checkbutton | 多选框控件;用于在程序中提供多项选择框 |
Entry | 输入控件;用于显示简单的文本内容 |
Frame | 框架控件;在屏幕上显示一个矩形区域,多用来作为容器 |
Label | 标签控件;可以显示文本和位图 |
Listbox | 列表框控件;在Listbox窗口小部件是用来显示一个字符串列表给用户 |
Menubutton | 菜单按钮控件,用于显示菜单项。 |
Menu | 菜单控件;显示菜单栏,下拉菜单和弹出菜单 |
Message | 消息控件;用来显示多行文本,与label比较类似 |
Radiobutton | 单选按钮控件;显示一个单选的按钮状态 |
Scale | 范围控件;显示一个数值刻度,为输出限定范围的数字区间 |
Scrollbar | 滚动条控件,当内容超过可视化区域时使用,如列表框。. |
Text | 文本控件;用于显示多行文本 |
Toplevel | 容器控件;用来提供一个单独的对话框,和Frame比较类似 |
Spinbox | 输入控件;与Entry类似,但是可以指定输入范围值 |
PanedWindow | PanedWindow是一个窗口布局管理的插件,可以包含一个或者多个子控件。 |
LabelFrame | labelframe 是一个简单的容器控件。常用与复杂的窗口布局。 |
tkMessageBox | 用于显示你应用程序的消息框。 |
标准属性
标准属性也就是所有控件的共同属性,如大小,字体和颜色等等。
属性 | 描述 |
---|---|
Dimension | 控件大小; |
Color | 控件颜色; |
Font | 控件字体; |
Anchor | 锚点; |
Relief | 控件样式; |
Bitmap | 位图; |
Cursor | 光标; |
实践1:制作一个BMI 计算器GUI程序
编写一个简单的界面,用户输入体重、身高,点击计算按钮,生成身体质量指数,简称体质数
示例代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import tkinter as tk
from tkinter import ttk # 主体控件命名模块
class BMIView(tk.Frame):
def __init__(self,parent,*args,**kwargs):
super().__init__(parent,*args,**kwargs) # parent 指的是当前这个控件容器将会依附在哪个容器或者窗体之上
self.body_weight = tk.DoubleVar()
self.height = tk.DoubleVar()
self.bmi = tk.StringVar()
lbl_body_weight = ttk.Label(self,text="体重(Kg):")
entry_body_weight = ttk.Entry(self,textvariable=self.body_weight)
lbl_height = ttk.Label(self,text="身高(m):")
entry_height = ttk.Entry(self,textvariable=self.height)
btn_calculate = ttk.Button(self,text="计算",command=self.on_calculate)
lbl_bmi = ttk.Label(self,textvariable=self.bmi,font=("Microsoft Yahei",64),wraplength=480)
lbl_body_weight.grid(row=0,column=0,sticky=tk.W)
entry_body_weight.grid(row=0,column=1,sticky=(tk.W+tk.E))
lbl_height.grid(row=0,column=2,sticky=(tk.W+tk.E))
entry_height.grid(row=0,column=3,sticky=(tk.W+tk.E))
btn_calculate.grid(row=0,column=4,sticky=(tk.E))
lbl_bmi.grid(row=1,column=0,columnspan=5) # columnspan=5 合并5个单元格
self.columnconfigure(1,weight=1)
self.columnconfigure(3,weight=1)
def on_calculate(self):
bmi = self.body_weight.get() / (self.height.get() ** 2)
print('bmi:',bmi)
self.bmi.set(f"{bmi:.1f}")
class BMIApplication(tk.Tk):
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.title("BMI 计算器")
self.geometry("640x180")
self.resizable(width=False,height=False)
BMIView(self).grid(sticky=(tk.E+tk.N+tk.W+tk.S))
self.columnconfigure(0,weight=1)
if __name__ == '__main__':
app = BMIApplication()
app.mainloop()
测试功能:
实践2:制作一个简单登录的GUI程序
输入用户名、密码,点击登录
AC1:输入正确用户名、密码,点击登录,弹窗提示登录成功
AC2:输入错误用户名或密码,点击登录,弹窗提示登录异常
# !/usr/bin/env python3
# -*- coding:utf-8 -*-
"""使用Entry组件的基本用法,使用面向对象的方式"""
import tkinter as tk
from tkinter import messagebox
class Application(tk.Frame):
def __init__(self,master=None):
super().__init__(master) # super()代表的是父类的定义,而不是父类对象
self.master = master
self.pack()
self.createWidget()
def createWidget(self):
global photo # 把photo声明成全局变量。如果是局部变量,本方法执行完毕后,图像对象销毁,窗口显示不出来
photo = tk.PhotoImage(file="imge/logo.png")
self.label03 = tk.Label(self, image=photo)
self.label03.pack()
"""创建界面登录的组件"""
self.label01 = tk.Label(self,text="用户名")
self.label01.pack()
# StringVar变量绑定到指定组件
# StringVar变量的值发生变化,组件内容也变化
# 组件内容发生变化,StringVar变量的值也发生变化
v1 = tk.StringVar()
self.entry01 = tk.Entry(self,textvariable=v1)
self.entry01.pack()
v1.set("admin")
"""创建密码框"""
self.label02 = tk.Label(self, text="密码")
self.label02.pack()
v2 = tk.StringVar()
self.entry02 = tk.Entry(self, textvariable=v2,show="*")
self.entry02.pack()
self.btn01 = tk.Button(self, text="登录", command=self.login)
self.btn01.pack()
def login(self):
username = self.entry01.get()
pwd = self.entry02.get()
if username == "admin" and pwd == "123456":
messagebox.showinfo("登录系统","登录成功!欢迎开始学习!")
else:
messagebox.showinfo("登录系统", "账号或密码错误,请重新输入")
root = tk.Tk()
root.geometry("400x300+600+400")
root.title("测试Entry")
app = Application(master=root)
if __name__ == '__main__':
root.mainloop()
实践3:操作TEXT的GUI程序
# !/usr/bin/env python3
# -*- coding:utf-8 -*-
"""使用Text组件的基本用法,使用面向对象的方式"""
import tkinter as tk
import webbrowser
class Application(tk.Frame):
def __init__(self,master=None):
super().__init__(master) # super()代表的是父类的定义,而不是父类对象
self.master = master
self.pack()
self.createWidget()
def createWidget(self):
self.w1 = tk.Text(root,width=40,height=12,bg="gray")
# 宽度20个字母(10个汉字),高度一个行高
self.w1.pack()
self.w1.insert(1.0,"0123456789\nabcdefghijklmn")
self.w1.insert(2.3,"锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦\n")
tk.Button(self,text="重复插入文本",command=self.insertText).pack(side="left")
tk.Button(self,text="返回文本",command=self.returnText).pack(side="left")
tk.Button(self,text="添加图片",command=self.addImage).pack(side="left")
tk.Button(self,text="添加组件",command=self.addWidget).pack(side="left")
tk.Button(self,text="通过tag精确控制文本",command=self.testTag).pack(side="left")
def insertText(self):
# INSERT索引表示在光标处插入
self.w1.insert(tk.INSERT,' test ')
# END索引表示在最后插入
self.w1.insert(tk.END,'[sxt]')
def returnText(self):
# Indexes(索引)是用来指向Text组件中文本的位置,Text的组件索引也是对应实际字符之间得位置
# 核心:行号以1开始,列号以0开始
print(self.w1.get(1.2,1.6))
self.w1.insert(1.8," test2 ")
print("所有文本内容:\n"+self.w1.get(1.0,tk.END))
def addImage(self):
self.photo = tk.PhotoImage(file="imge/logo.png")
self.w1.image_create(tk.END,image=self.photo)
def addWidget(self):
b1 = tk.Button(self.w1,text="测试TEXT")
# 在text创建组件的命令
self.w1.window_create(tk.INSERT,window=b1)
def testTag(self):
self.w1.delete(1.0,tk.END)
self.w1.insert(tk.INSERT,"good good study,day day up!\n前端开发\n后端开发\n测试设计")
self.w1.tag_add("good",1.0,1.9)
self.w1.tag_config("good",background="yellow",foreground="red")
self.w1.tag_add("baidu",4.0,4.2)
self.w1.tag_config("baidu",underline=True)
self.w1.tag_bind("baidu","<Button-1>",self.webshow)
def webshow(self,event):
webbrowser.open("https://www.baidu.com")
root = tk.Tk()
root.geometry("500x250+600+400")
root.title("测试TEXT")
app = Application(master=root)
if __name__ == '__main__':
root.mainloop()