tkinter
python的PEP8规范:PEP 8 – Style Guide for Python Code | peps.python.org
基于tkinter模块创建GUI程序包含如下4个核心步骤:
-
创建应用程序主窗口对象(也称:根窗口)
-
通过类
Tk
的无参构造函数from tkinter inport * root = Tk()
-
-
在主窗口中,添加各种可视化组件,比如:按钮(Button)、文本框(Label)等。
btn01 = Button(root) btn01["text"] = "点我就送花"
-
通过几何布局管理器,管理组件的大小和位置
btn01.pack()
-
事件处理
-
通过绑定事件处理程序,响应用户操作所触发的事件(比如:单机、双击)
def songhua(e): messagebox.showinfo("Message","送你一朵玫瑰花,请你爱上我") print("送你99朵玫瑰花") btn01.bind("<Button-1>",songhua)
-
【示例】使用tkinter模块,创建GUI应用程序,并实现点击按钮的事件处理
from tkinter import *
from tkinter import messagebox
root = Tk()
btn01 = Button(root)
btn01["text"] = "点我送花"
btn01.pack()
def songhua(e):
messagebox.showinfo("Message","送你一朵玫瑰花,请你爱上我!")
print("送你99朵玫瑰花")
btn01.bind("<Button-1>", songhua)
root.mainloop() # 调用组件 mainloop 方法, 进入事件循环
tkinter 主窗口
主窗口位置和大小
通过 geometry ('wxh±x±y')进行设置。w为宽度,h为高度。+x 表示距屏幕左边的距离;-x 表示距屏幕右边的距离;+y表示距屏幕上边的距离;-y 表示 距屏幕下边的距离。
from tkinter import *
from tkinter import messagebox
root = Tk()
root.title("我的第一个GUI程序")
root.geometry("500x300+300+200")
GUI 编程整体描述
图像用户界面是由一个个组件组成,就像小孩“搭积木”一样最终组成了整个界面,有的组件还能在里面再放置其他组件,我们称为 “容器” 。Tkinter 的 GUI 组件关系图如下:
根据上图所示,我们依次简介这些类的基本作用。
-
Misc 和 Wm
-
Tkinter 的 GUI 组件有两个根父类,它们都直接继承了 object 类:
-
Misc:它是所有组件的根父类。
-
Wm:它主要提供了一些与窗口管理器通信的功能函数。
-
-
-
Tk
Misc 和 Wm派生出子类Tk,它代表应用程序的主窗口,一般应用程序都需要直接或间接使用Tk。
- Pack、Place、Grid
- Pack、Place、Grid 是布局管理器,布局管理器管理组件的:大小、位置。通过布局管理器可以将容器中的组件实现合理的排布。
- BaseWidget
- BaseWidget 是 所有组件的父类
- Widget
- Widget 是 所有组件的父类,Widget 一共有四个父类:BaseWidget、Pack、Grid、Place。意味着,所有 GUI 组件同时具备这四个父类的属性和方法。
【注】想观察的层次结构可以在类定义处的类名上单击右键,选择 Diagram --> Show Diagram
常用组件汇总列表
Tkinter类 | 名称 | 简介 |
---|---|---|
Toplevel | 顶层 | 容器类,可用于为其他组件提供单独的容器;Toplevel有点类似于窗口 |
Button | 按钮 | 代表按钮组件 |
Canvas | 画布 | 提供绘图功能,包括直线、矩形、椭圆、多边形、位图等 |
Checkbutton | 复选框 | 可供用户勾选的复选框 |
Entry | 单行输入框 | 用户可输入内容 |
Frame | 容器 | 用于装载其它 GUI 组件 |
Label | 标签 | 用于像是不可编辑的文本或图标 |
LabelFrame | 容器 | 也是容器组件,类似于Frame,但它支持添加标题 |
Listbox | 列表框 | 列出多个选项,供用户选择 |
Menu | 菜单 | 菜单组件 |
Menubutton | 菜单按钮 | 用来包含菜单的按钮(包括下拉式、层叠式等) |
OptionMenu | 菜单按钮 | Menubutton 的子类,也代表菜单按钮,可通过按钮打开一个菜单 |
Message | 消息框 | 类似于标签,但可以显示多行文本;后来当 Label 也能显示多行文本之后,该组件基本处于废弃状态 |
PanedWindow | 分区窗口 | 该容器会被划分成多个区域,每添加一个组件占一个区域,用户可通过拖动分隔线来改变各区域的大小 |
Radiobutton | 单选按钮 | 可供用户点边的单选钮 |
Scale | 滑动条 | 拖动滑块可设定起始值和结束值,可显示当前位置的精确值 |
Spinbox | 微雕选择器 | 用户可通过该组件的向上、向下箭头选择不同的值 |
Scrollbar | 滚动条 | 用于为组件(文本域、画布、列表框、文本框)提供滚动功能 |
Text | 多行文本框 | 显示多行文本 |
GUI 应用程序类的经典写法
本节程序也是 GUI 应用程序编写的一个主要结构,采用了面向对象的方式,更加合理的组织代码。
通过类Application 组织整个 GUI 程序,类Application继承了 Frame 及通过继承拥有了父类的特性。通过构造函数__init__()
初始化窗口中的对象,通过 createWidgets() 方法创建窗口中的对象。
Frame 框架是一个 tkinter 组件,表示一个矩形的区域。Frame 一般作为容器使用,可以放置其他组件,从而实现复杂的布局。
Label标签
Label (标签) 主要用于显示文本信息,也可以显示图像。
Label (标签) 有这样一些常见属性:
-
width, height:
- 用于指定区域大小,如果显示是文本,则以单个英文字符大小为单位(一个汉字宽度占2个字符位置,高度和英文字符一样);如果显示图像,则以像素为单位。默认值是根据具体显示的内容动态调整。
-
font
指定字体和字体大小,如:font = (font_name,size)
-
image:
显示在Label上的图像,目前 tkinter 只支持 GIF 格式。
-
fg 和 bg
fg (foreground):前景色、bg(background): 背景色
-
justify
针对多行文字的对齐,可设置 justify 属性, 可选值 "left", “center” or “right”
Option 选项详解
通过学习 Label 组件, 我们发现可以通过Options 设置组件的属性,从而控制组件各种状态,比如:宽度、高度、颜色、位置等等。
我们可以通过三种方式设置Options 选项,这在各种 GUI 组件中用法都一致。
-
创建对象时,使用命名参数(也叫关键字参数)
fred = Button(self, fg="red", bg="blue")
-
创建对象后,使用字典引方式
fred["fg"] = "red" fred["bg"] = "blue"
-
创建对象后,使用 config() 方法
fred.config(fg="red", bg="blue")
-
Button
Button(按钮)用来执行用户的单机操作。Button 可以包含文本,也可以包含图像。按钮被单击后会自动调用对应事件绑定的方法。
"""使用面向对象的方式,测试一个经典的 GUI 程序的写法,使用面向对象的方式""" from tkinter import * from tkinter import messagebox class Application(Frame): """一个经典的GUI程序的类写法""" def __init__(self, master=None): super().__init__(master) # super() 代表的是父类的定义, 而不是父类对象 self.master = master self.pack() self.createWidget() def createWidget(self): """创建组件""" self.btn01 = Button(root, text="登录", command=self.login) self.btn01.pack() # 显示图像 global photo # 把photo声明成全局变量。如果是局部变量,本方法执行完毕后,图像对象销毁,窗口显示不出图像。 photo = PhotoImage(file="picture/OGC2.gif") self.btn02 = Button(root, image=photo, command=self.login) self.btn02.pack() # self.btn02.config(state="disabled") # 设置按钮为禁用 def login(self): messagebox.showinfo("尚学堂学习系统", "登录成功!欢迎开始学习!") if __name__ == '__main__': root = Tk() root.geometry("800x1000+200+300") root.title("button测试") app = Application(master=root) root.mainloop()
-
Entry 单行文本框
Entry 用来接收一行字符串的控件。如果用户输入的文字长度长于 Entry 控件的宽度时,文字会自动向后滚动。如果想输入多行文本,需要使用 Text 控件。
"""使用面向对象的方式,测试一个经典的 GUI 程序的写法,使用面向对象的方式""" from tkinter import * from tkinter import messagebox class Application(Frame): """一个经典的GUI程序的类写法""" def __init__(self, master=None): super().__init__(master) # super() 代表的是父类的定义, 而不是父类对象 self.master = master self.pack() self.createWidget() def createWidget(self): """创建登录界面的组件""" self.label01 = Label(self, text="用户名") self.label01.pack() # StringVar 变量绑定到指定的组件。 # StringVar 变量的植发生变化,组件内容也变化: # 组件内容发生变化,StringVar 变量的值也发生变化, v1 = StringVar() self.entry01 = Entry(self, textvariable=v1) self.entry01.pack() v1.set("admin") print(v1.get());print(self.entry01.get()) # 创建密码框 self.label02 = Label(self, text="密码") self.label02.pack() v2 = StringVar() self.entry02 = Entry(self, textvariable=v2, show="*") self.entry02.pack() Button(self, text="登陆", command = self.login).pack() def login(self): username = self.entry01.get() pwd = self.entry02.get() print("去数据库比对用户名和密码!") print("用户名:"+username) print("密码:"+pwd) if username == "gaoqi" and pwd == "123456": messagebox.showinfo("尚学堂学习系统", "登录成功!欢迎开始学习!") else: messagebox.showinfo("尚学堂学习系统","登录失败!用户名或密码错误!") if __name__ == '__main__': root = Tk() root.geometry("400x130+200+300") root.title("button测试") app = Application(master=root) root.mainloop()
-
Text多行文本框
Txt(多行文本框)的主要用于显示多行文本,还可以显示网页链接,图片,HTML页面,甚至CSS样式表,添加组件等。因此,也常被当做简单的文本处理器、文本编辑器或者网页浏览器来使用。比如IDLE就是Text组件构成的。
"""使用面向对象的方式,测试一个经典的 GUI 程序的写法,使用面向对象的方式""" from tkinter import * import webbrowser class Application(Frame): """一个经典的GUI程序的类写法""" def __init__(self, master=None): super().__init__(master) # super() 代表的是父类的定义, 而不是父类对象 self.master = master self.pack() self.createWidget() def createWidget(self): self.w1 = Text(root, width=40, height=12, bg="gray") # 宽废20个字母(10个汉字),高度一个行高 self.w1.pack() self.w1.insert(1.0, "0123456789\nabcdefg") self.w1.insert(2.3, "锄禾日当午,汗滴禾下土。谁知盘中餐,粒粒皆辛苦\n") Button(self, text="重复插入文本", command=self.insertText).pack(side="left") Button(self, text="返回文本", command = self.returnText).pack(side="left") Button(self, text="添加图片", command = self.addImage).pack(side="left") Button(self, text="添加组件", command = self.addwidget).pack(side="left") Button(self, text="通过tag精确控制文本", command=self.testTag).pack(side="left") def insertText(self): # INSERT索引表示在光标处插入 self.w1.insert(INSERT,'Gaoqi') # EWD索引号表示在最后插入 self.w1.insert(END, '【sxt】') self.w1.insert(1.8, "gaoqi") def returnText(self): # Indexes(索引)是用来指向Text组件中文本的位置,Text的组件索引也是对应实际字符之间的位置。 # 核心:行号以1开始 列号以0开始 print(self.w1.get(1.2, 1.6)) print("所有文本内容:\n"+self.w1.get(1.0,END)) def addImage(self): # global photo self.photo = PhotoImage(file="picture/OGC4.gif") self.w1.image_create(END, image=self.photo) def addwidget(self): b1 = Button(self.w1, text='爱尚学堂') # 在teXt仓创建组件的命令 self.w1.window_create(INSERT, window=b1) def testTag(self): self.w1.delete(1.0, END) self.w1.insert(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("http://www.baidu.com") if __name__ == '__main__': root = Tk() root.geometry("400x130+200+300") root.title("button测试") app = Application(master=root) root.mainloop()
Radiobutton单选按钮
Radiobutton控件用于选择同一组单选按钮中的一个.
Radiobutton可以显示文本,也可以显示图像.
【示例】Radiobutton基础用法"""测试Radiobutton组件的基本用法,使用面向对象的方式""" from tkinter import * from tkinter import messagebox class Application(Frame): """一个经典的GUI程序的类写法""" def __init__(self, master=None): super().__init__(master) # super() 代表的是父类的定义, 而不是父类对象 self.master = master self.pack() self.createWidget() def createWidget(self): self.v = StringVar(); self.v.set("F") self.r1 = Radiobutton(self, text="男性", value="M", variable=self.v) self.r2 = Radiobutton(self, text="女性", value="F", variable=self.v) self.r1.pack(side="left");self.r2.pack(side="left") Button(self, text="确定", command = self.confirm).pack(side="left") def confirm(self): messagebox.showinfo("测试", "选择的性别:" + self.v.get()) if __name__ == '__main__': root = Tk() root.geometry("400x130+200+300") root.title("Radiobutton测试") app = Application(master=root) root.mainloop()
Checkbutton复选按钮
Checkbutton控件用于选择多个按钮的情况。Checkbutton可以显示文本,也可以显示图像。【示例】Checkbutton复选按钮用法
"""测试Checkbutton组件的基本用法,使用面向对象的方式""" """使用面向对象的方式,测试一个经典的 GUI 程序的写法,使用面向对象的方式""" from tkinter import * from tkinter import messagebox class Application(Frame): """一个经典的GUI程序的类写法""" def __init__(self, master=None): super().__init__(master) # super() 代表的是父类的定义, 而不是父类对象 self.master = master self.pack() self.createWidget() def createWidget(self): self.codeHobby = IntVar(); self.videoHobby = IntVar() print(self.codeHobby.get()) # 默认值是0 self.c1 = Checkbutton(self, text="敲代码", variable=self.codeHobby, onvalue=1, offvalue=0) self.c2 = Checkbutton(self, text="看视须", variable=self.videoHobby, onvalue=1, offvalue=0) self.c1.pack(side="left"); self.c2.pack(side="left") Button(self, text="确定", command=self.confirm).pack(side="left") def confirm(self): if self.videoHobby.get() == 1: messagebox.showinfo("测试","看视频,都是正常人有的爱好I你喜欢看什么类型?") if self.codeHobby.get() == 1: messagebox.showinfo("测试","抓获野生程序猿一只,赶紧送给他尚学堂的视频充饥") if __name__ == '__main__': root = Tk() root.geometry("400x130+200+300") root.title("Radiobutton测试") app = Application(master=root) root.mainloop()
canvas画布
canvas(画布)是一个矩形区域,可以放置图形、图像、组件等。本节我们简单介绍canvas的使用,更加详细和深入的内容将在后面的“图形绘制”章节讲解.