Python图形化编程入门,使用的是python自带的Tkinter模块,能够满足大多数的应用场景,使用简单。
import tkinter # 导入tkinter库
tk = tkinter.Tk() # 创建一个tk对象
tk.title('This is a test!') # 设置图形框名
tk.mainloop() # 进入消息循环,即显示窗口
可以使用geometry()方法来设置窗口的大小
tk.geometry("300x200")
还可以使用minsize()方法和maxsize()方法设置最小和最大窗口尺寸
(宽,高)
tk.minsize(300,100)
tk.maxsize(500,400)
Tkinter几何布局管理器(Geometry Manager)用于组织和管理父组件(往往是窗口)中子组件的布局方式。Tkinter提供了三种风格的几何布局管理类:pack、grid和place。
pack几何布局管理器采用块的方式组织组件。pack布局可根据子组件创建生成的顺序。
调用子组件的方法pack(),则该子组件在其父组件中采用pack布局:
例:
import tkinter
tk = tkinter.Tk()
tk.title('This is a test!')
tk.geometry("300x200")
label = tkinter.Label(tk,text="Hello world!")
label.pack() # 默认放置
button1 = tkinter.Button(tk, text='button1')
button1.pack(side=tkinter.LEFT) # 将button1靠左放置
button2 = tkinter.Button(tk, text='button2')
button2.pack(side=tkinter.RIGHT) # 将button2靠右放置
tk.mainloop()
grid几何布局管理器采用表格结构组织组件。子组件的位置由行/列确定的单元格决定,子组件可以跨越多行/列。在每一列中,列宽由这一列中最宽的单元格确定。采用grid布局,适合于表格形式的布局,可以实现复杂的界面。
调用子组件的grid()方法,则该子组件在其父组件中采用grid布局:
grid()方法中两个最为重要的参数,一个是row,另一个是column。它们可用来指定将子组件放置到什么位置,如果不指定row,则会将子组件放置到第一个可用的行上;如果不指定column,则使用第0列(首列)。
例:
from tkinter import *
tk = Tk()
tk.title('This is a test!')
tk.geometry("300x200+250+250") # 250、250表示初始化时窗口的位置
button1 = Button(tk,text='0,0')
button2 = Button(tk,text='0,1')
button3 = Button(tk,text='0,2')
button4 = Button(tk,text='1,0')
button1.grid(row=0,column=0) # 放置在第1行第1列
button2.grid(row=0,column=1) # 放置在第1行第2列
button3.grid(row=0,column=2) # 放置在第1行第3列
button4.grid(row=1,column=0,columnspan=2,sticky=E+W) # 放置在第2行跨2列,左右填充
tk.mainloop()
place几何布局管理器允许开发者指定组件的大小与位置。place的优点是可以精确控制组件的位置;缺点是改变窗口大小时,子组件不能随之灵活改变大小。
调用子组件的方法place(),则该子组件在其父组件中采用place布局:
例:
from tkinter import *
tk = Tk()
tk.title('Login')
tk['width'] = 250;tk['height'] = 80
Label(tk, text='username', width=8).place(x=1, y=1) # 绝对坐标(1,1)
Entry(tk, width=20).place(x=65, y=1) # 绝对坐标(45,1)
Label(tk, text='password', width=8).place(x=1, y=20) # 绝对坐标(1,20)
Entry(tk, width=20, show='*').place(x=65, y=24) # 绝对坐标(45,20)
Button(tk, text='login', width=6).place(x=40, y=48)
Button(tk, text='cancel', width=6).place(x=110, y=48)
tk.mainloop()
Tkinter提供各种组件(控件),如按钮、标签和文本框,可在一个GUI应用程序中使用。
通过组件类的构造函数可以创建对象实例。例如:
from tkinter import *
tk = Tk()
b = Button(tk, text='button')
组件标准属性也就是所有组件(控件)的共同属性,如大小、字体和颜色等。常见属性如下:
可以通过下列几种方式设置组件属性。
b = Button(tk, text='button') # 按钮组件的构造函数
b.config(text='button') # 组件对象的config()方法的命名参数
b['text'] = 'button' # 组件对象的属性赋值
Label组件用于在窗口中显示文本或位图。Anchor属性指定文本(text)或图像(bitmap/image)在Label中的显示位置(其他组件同此)。对应于东南西北中以及四个角,可用值如下:
默认情况下,是在中间即对应值为center
Label(tk, text='hello world',anchor='center').pack()
Label(tk, bitmap='question').pack()
bm = PhotoImage(file=r'./1.png') # 创建图片对象
Label(tk,image=bm).pack() # 插入图片
Button组件(控件)是一个标准的Tkinter部件,用于实现各种按钮功能。按钮可以包含文本或图像,可以通过command属性将调用Python函数或方法关联到按钮上。当这些按钮被按下时,就会自动调用该函数或方法。
单行文本框组件主要用于输入单行内容和显示文本,可以方便地向程序传递用户参数。
get()方法用于获取单行文本框内输入的内容。
设置或者获取单行文本框组件的内容也可以使用StringVar()对象来完成,把单行文本框组件的textvariable属性设置为StringVar()变量,再通过StringVar()变量的get()和set()函数可以读取和输出相应文本内容。例如:
s = StringVar() # 创建一个StringVar()对象
s.set("Hello world!") # 设置文本内容
entry = Entry(tk, textvariable=s) # 显示内容
print(s.get()) # 打印出"Hello world"
单行文本框组件的常用属性:
参数 | 值 |
---|---|
show | 如果设置为字符*,则输入文本框内显示为*,用于密码输入。 |
insertbackground | 插入光标的颜色,默认为黑色’black’。 |
selectbackground和selectforeground | 选中文本的背景色与前景色。 |
width | 组件的宽度(所占字符个数)。 |
fg | 字体前景颜色。 |
bg | 背景颜色。 |
state | 设置组件状态,默认为normal,可设置为:disabled禁用组件,readonly只读。 |
列表框(Listbox)组件可用于显示多个项目,并且允许用户选择一个或多个项目。
该组件的创建方法和布局方式,与之前的组件类似。
可以使用insert()方法向列表框组件中插入文本项
listbox对象.insert(index, item)
其中:index是插入文本项的位置,如果在尾部插入文本项,则可以使用END;如果在当前选中处插入文本项,则可以使用ACTIVE。Item是要插入的文本项。
listbox对象.curselection()
返回当前选中项目的索引,结果为元组。索引号从0开始,0表示第一项。
listbox对象.delete(first_index,last_index)
删除指定范围(first_index,last_index)的项目,不指定last_index时,删除一个项目。
删除范围包括两边。
与删除项函数类似。
listbox对象.get(first_index,last_index)
listbox对象.size()
需要使用listvariable属性为Listbox对象指定一个对应的变量,例如:
m = StringVar()
listbox = Listbox(tk, listvariable=m)
listbox.insert(0, 'a')
print(m.get())
指定后就可以使用m.get()方法获取Listbox对象中的内容了。
注意:如果允许用户选择多个项目,则需要将Listbox对象的selectmode属性设置为MULTIPLE,表示多选;若设置为SINGLE,则表示单选。
创建从一个列表框选择内容添加到另一个列表框组件的GUI程序。
from tkinter import *
tk = Tk()
tk.title('Listbox')
tk['width'] = 250;tk['height'] = 80
def add():
for i in listb1.curselection(): # 遍历选中项
listb2.insert(0,listb1.get(i)) # 添加到右侧列表框
def delete():
for i in listb2.curselection(): # 遍历选中项
listb2.delete(i) # 从右侧列表框中删除
lis = ['a','b','c']
listb1 = Listbox(tk)
listb2 = Listbox(tk)
for item in lis: # 给左侧列表框循环插入选项
listb1.insert(0,item)
listb1.grid(row=0, column=0, rowspan=2)
b1 = Button(tk, text='add', command=add, width=20)
b2 = Button(tk, text='delete', command=delete, width=20)
b1.grid(row=0, column=1)
b2.grid(row=1, column=1)
listb2.grid(row=0, column=2, rowspan=2)
tk.mainloop()
单选按钮和复选框分别用于实现选项的单选和复选功能。Radiobutton组件用于在同一组单选按钮中选择一个单选按钮(不能同时选定多个)。Checkbutton组件用于选择一项或多项。
这连个组件的创建与显示方法与其他组件类似。
可以使用variable属性为Radiobutton组件指定一个对应的变量。如果将多个Radiobutton组件绑定到同一个变量,则这些Radiobutton组件属于同一个分组。分组后需要使用value设置每个Radiobutton组件的值,以标识该项目是否被选中。
参数 | 描述 |
---|---|
variable | 单选按钮索引变量,通过变量的值确定哪个单选按钮被选中。一组单选按钮使用同一个索引变量。 |
value | 单选按钮选中时变量的值。 |
command | 单选按钮选中时执行的命令(函数)。 |
方法名 | 描述 |
---|---|
deselect() | 取消选择。 |
select() | 选择。 |
invoke() | 调用单选按钮command指定的回调函数。 |
参数 | 描述 |
---|---|
variable | 复选框索引变量,通过变量的值确定哪些复选框被选中。每个复选框使用不同的变量,复选框之间相互独立。 |
onvalue | 复选框选中(有效)时变量的值。 |
offvalue | 复选框未选中(无效)时变量的值。 |
command | 复选框选中时执行的命令(函数)。 |
为了弄清楚Checkbutton组件是否被选中,需要使用variable属性为Checkbutton组件指定一个对应变量,例如:
c = IntVar()
c.set(1)
check = Checkbutton(tk, text='a', variable=c, onvalue=1, offvalue=2) # 1为选中,2为没选中
check.pack()
print(c.get())
指定变量c后,可以使用c.get()获取复选框的状态值,也可以使用c.set()设置复选框的状态。例如,设置check复选框对象为未选中状态,代码如下:
c.set(1) # 1为选中,2为没选中
获取单选按钮(Radiobutton)状态的方法类似。
from tkinter import *
tk = Tk()
tk.title('Listbox')
tk['width'] = 250;tk['height'] = 80
v = StringVar()
v.set('3') # 设置初始选项值
Radiobutton(tk, variable=v, value='1', text='a').pack()
Radiobutton(tk, variable=v, value='2', text='b').pack()
Radiobutton(tk, variable=v, value='3', text='c').pack()
tk.mainloop()
print(v.get())
图形用户界面应用程序通常提供菜单,菜单包含各种按照主题分组的基本命令。图形用户界面应用程序包括如下两种类型的菜单。
主菜单:提供窗体的菜单系统。通过单击可显示下拉子菜单,选择其中的命令可执行相关的操作,常用的主菜单通常包括:文件、编辑、视图、帮助等。
上下文菜单(也称为快捷菜单):通过右击某对象而弹出的菜单,一般为与该对象相关的常用菜单命令,例如,剪切、复制、粘贴等。
例:
from tkinter import *
tk = Tk()
def click():
print('cilck')
menu = Menu(tk) # 创建菜单对象
for item in ['file', 'edite', 'view']: # 添加菜单标签
menu.add_command(label=item, command=click) # 给标签添加事件
tk['menu'] = menu # 附加主菜单到窗口
tk.mainloop()
消息窗口(Messagebox)用于弹出提示框进行告警,或选择下一步的操作。消息框包括很多类型,常用的有info、warning、error、yesno、okcancel等,包含不同的图标、按钮以及弹出提示音。
例:
import tkinter as tk
from tkinter import messagebox as msgbox
m = tk.Tk()
m.title("MsgBox")
def b1_click():
msgbox.showinfo("Info", "Showinfo.")
def b2_click():
msgbox.showwarning("Warning", "Showwarning.")
def b3_click():
msgbox.showerror("Error", "Showerror.")
def b4_click():
msgbox.askquestion("Question", "Askquestion.")
def b5_click():
msgbox.askokcancel("OkCancel", "Askokcancel.")
def b6_click():
msgbox.askyesno("YesNo", "Askyesno.")
def b7_click():
msgbox.askretrycancel("Retry", "Askretrycancel.")
tk.Button(m, text='showinfo', command=b1_click).pack(fill=tk.X)
tk.Button(m, text='showwarning', command=b2_click).pack(fill=tk.X)
tk.Button(m, text='showerror', command=b3_click).pack(fill=tk.X)
tk.Button(m, text='askquestion', command=b4_click).pack(fill=tk.X)
tk.Button(m, text='askokcancel', command=b5_click).pack(fill=tk.X)
tk.Button(m, text='askyesno', command=b6_click).pack(fill=tk.X)
tk.Button(m, text='askretrycancel', command=b7_click).pack(fill=tk.X)
m.mainloop()
Frame组件是框架组件,负责安排其他组件的位置。Frame组件在屏幕上显示为一个矩形区域,可作为显示其他组件的容器。
创建对象
Frame对象=Frame(窗口对象, height=高, width=宽, bg=背景色)
显示对象
Frame对象.pack()
在创建组件时可以指定其容器为Frame组件即可
Label(Frame对象, text='hello').pack()
LabelFrame组件是有标题的Frame组件,可以使用text属性设置LabelFrame组件的标题,方法如下:
LabelFrame(窗口对象, height=高, width=宽, text=标题).pack()
from tkinter import *
tk = Tk()
tk.title('Frame')
f1 = Frame(tk)
f1.pack()
f2 = Frame(tk)
f2.pack()
lf = LabelFrame(tk,text='label_frame')
lf.pack(side=BOTTOM)
Button(f1, text='f1_button1', fg='red').pack(side=LEFT)
Button(f1, text='f1_button2', fg='brown').pack(side=LEFT)
Button(f1, text='f1_button3', fg='blue').pack(side=LEFT)
Button(f2, text='f2_button', fg='black').pack()
Button(lf, text='lf_button', fg='green').pack()
tk.mainloop()
用Python制作GUI图形界面,可以使用after()方法每隔几秒刷新GUI图形界面。例如,通过下面代码可实现计数器的功能,并且文字背景色会不断地改变。
from tkinter import *
tk = Tk()
colors = ('red', 'yellow', 'blue', 'green', 'orange')
f = Frame(tk, height=200, width=200)
f.color = 0
f['bg'] = colors[f.color] # 设置框架背景色
lab1 = Label(f, text='0')
lab1.pack()
def foo():
f.color = (f.color+1) % (len(colors))
lab1['bg'] = colors[f.color]
lab1['text'] = str(int(lab1['text'])+1)
f.after(500, foo) # 每隔500毫秒就执行foo函数刷新屏幕
f.pack()
f.after(500, foo)
tk.mainloop()
我们可以使用after()方法实现移动电子广告效果,只需不断移动lab1即可,代码如下:
from tkinter import *
tk = Tk()
f = Frame(tk, height=200, width=200)
lab1 = Label(f, text='hello world')
x = 0
def foo():
global x
x = x+10
if x>200:
x = 0
lab1.place(x=x, y=0)
f.after(500, foo)
f.pack()
f.after(500, foo)
tk.mainloop()
通过组件的font属性,可以设置其显示文本的字体。设置组件字体前首先要能表示一个字体。
通过三个元素的元组,可以表示字体:
(font family, size, modifiers)
素font family是字体名;size为字体大小,单位为point;modifiers为包含粗体、斜体、下画线的样式修饰符。例如:
('Time New Roman', 16, 'bold italic')
例,通过元组表示字体,设置标签label的字体:
from tkinter import *
tk = Tk()
fts = ('Arial', ('Courier New', 19, 'italic'), ('Comic Sans MS',), 'Fixdsys', ('MS Sans Serif',), ('MS Serif',), 'Symbol', 'System', ('Times New Roman',), 'Verdana')
for ft in fts:
Label(tk, text='hello sticky', font=ft).grid()
tk.mainloop()
可以使用tkFont.Font来创建字体。格式如下:
Font(family='字体名', size, weight, slant, underline, overstrike)
其中:size为字体大小;weight=‘bold’或’normal’,'bold’为粗体;slant=‘italic’或’normal’,'italic’为斜体;underline=1或0,1为下画线;overstrike=1或0,1为删除线。
例:
from tkinter import *
from tkinter.font import Font
tk = Tk()
ft = Font(family='Helvetica', size=36, weight='bold')
Label(tk, text='Hello stick', font=ft).grid()
tk.mainloop()
通过tkFont. families()函数可以返回所有可用的字体。
事件(Event)就是程序中发生的事,例如,用户敲击键盘上的某一个键或单击、移动鼠标。对于这些事件,程序需要做出反应。Tkinter提供的组件通常都有自己可以识别的事件,例如,当按钮被单击时执行特定的操作或当一个输入栏成为焦点,而用户又敲击了键盘上的某些按键,用户所输入的内容就会显示在输入栏内。
程序可以使用事件处理函数来指定当触发某个事件时所做的反应(操作)。
事件类型的通用格式:
<[modifier-]...type[-detail]>
事件类型必须放置于尖括号<>内。type描述了类型,例如,键盘按键、鼠标单击。
modifier用于组合键定义,如Control、Alt。detail用于明确定义是哪一个键或按钮的事件,例如,1表示鼠标左键,2表示鼠标中键,3表示鼠标右键。
举例:
# 按下鼠标左键
# 按下A键
# 同时按下Control、Shift、A三键
Python中事件主要有:键盘事件、鼠标事件、窗体事件。
键盘事件
名称 | 描述 |
---|---|
KeyPress | 按下键盘某键时触发,可以在 detail部分指定是哪个键 |
KeyRelease | 释放键盘某键时触发,可以在 detail部分指定是啷个键 |
鼠标事件
名称 | 描述 |
---|---|
Button Press或 Button | 按下鼠标某键,可以在deta部分指定是哪个键 |
Button Release | 释放键盘某键时触发,可以在 detail部分指定是啷个键 |
Motion | 点中组件的同时拖曳组件移动时触发 |
Enter | 当鼠标指针移进某组件时触发 |
Leave | 当鼠标指针移出某组件时触发 |
MouseWheel | 当鼠标滚轮滚动时触发 |
窗体事件
名称 | 描述 |
---|---|
Visibility | 当组件变为可视状态时触发 |
Unmap | 当组件由显示状态变为隐藏状态时触发 |
Map | 当组件由隐藏状态变为显示状态时触发 |
Expose | 当组件从原本被其他组件遮盖的状态中暴露出来时触发 |
FocusIn | 组件获得焦点时触发 |
FocusOut | 组件失去焦点时触发 |
Configure | 当改变组件大小时触发,如拖曳窗体边缘 |
Property | 当窗体的属性被删除或改变时触发,属于 Tkinter的核心事件 |
Destroy | 当组件被销毁时触发 |
Activate | 与组件选项中的 state项有关,表示组件由不可用转为可用,如按钮由disabled(灰色)转为 enabled |
Deactivate | 与组件选项中的stae项有关,表示组件由可用转为不可用,如按钮由enabled转为 disabled(灰色) |
modifier组合键定义中常用的修饰符
修饰符 | 描述 |
---|---|
Alt | 当按下【A】键 |
Any | 按下任何键,如 |
Control | 按下【ct】键 |
Double | 两个事件在短时间内发生,如双击鼠标左键< Double- Button-1> |
Lock | 当按下【 Caps Lock】键 |
Shift | 当按下【Shif】键 |
Triple | 类似于 Double,三个事件在短时间内发生 |
可以短格式表示事件,例如:<1>等同于,等同于。
对于大多数的单字符按键,用户还可以忽略“<>”符号。但是空格键和尖括号键不能忽略(正确的表示方式分别为、)。
程序建立一个处理某一事件的事件处理函数,称之为绑定。
创建组件对象时绑定
创建组件对象实例时,可通过其命名参数command绑定事件处理函数。例如:
def callback():
showinfo("hello")
Button(tk, text="hello", command=callback).pack()
实例绑定
调用组件对象实例方法bind()可为指定组件实例绑定事件,这是最常用的事件绑定方式。
组件对象实例名.bind("<事件类型>", 事件处理函数)
假设声明了一个名为canvas的Canvas组件对象,若要在canvas上按下鼠标左键时绘制一条线,可以这样实现:
canvas.bind('', drawline)
其中,bind()函数的第一个参数是事件描述符,指定无论什么时候在canvas上,当按下鼠标左键时就调用事件处理函数drawline进行绘制线条的任务。特别需要注意的是:drawline后面的圆括号是省略的,Tkinter会将此函数填入相关参数后调用运行,在这里只是声明而已。
标识绑定
在Canvas画布中绘制各种图形,将图形与事件绑定可以使用标识绑定tag_bind()函数。预先为图形定义标识tag后,再通过标识tag来绑定事件。例如:
cv.tag_bind('r1', '', printRect)
示例:
from tkinter import *
tk = Tk()
def printRect1(event):
print('rectangle左键事件')
def printRect2(event):
print('rectangle右键事件')
def printLine(event):
print('Line事件')
cv = Canvas(tk, bg='white') # 创建一个Canvas,设置其背景为白色
rt1 = cv.create_rectangle(10, 10, 110, 110, width=8, tags='r1')
cv.tag_bind('r1', '' , printRect1) # 绑定item与鼠标左键事件
cv.tag_bind('r1', '' , printRect2) # 绑定item与鼠标右键事件
# 创建一个line,并将其tags设置为'r2'
cv.create_line(180, 70, 280, 70, width=10, tags='r2')
cv.tag_bind('r2', '' , printLine) # 绑定item与鼠标左键事件
cv.pack()
tk.mainloop()
这个示例中,单击矩形的边框时才会触发事件,矩形既响应鼠标左键又响应右键。使用鼠标左键单击矩形边框时出现“rectangle左键事件”信息,使用鼠标右键单击矩形边框时出现“rectangle右键事件”信息,使用鼠标左键单击直线时则出现“Line事件”信息。
定义事件处理函数
事件处理函数往往带有一个event参数。触发事件调用事件处理函数时,将传递Event对象实例。
def callback(event): # 事件处理函数
showinfo("info")
Event事件处理参数属性
可以获取Event对象实例的各种相关参数,Event事件对象的主要参数属性如下
参数 | 说明 |
---|---|
.x,.y | 鼠标相对于组件对象左上角的坐标 |
.x_roo,.y_roo | 鼠标相对于屏幕左上角的坐标 |
.keysym | 字符串命名按键,例如: Escape、F1~F12、 Scroll lock、 Pause、 Insert、Delete、Home、 Prior(这个是 Page Up)、Next(这个是 Page Down)End、Up、 Right、Left、Down、 Shit L、 Shift R、 Contro_L、 Control_R、AltR、WinL |
.keysym_num | 数字代码命名按键 |
.keycode | 键码,但是它不能反映事件前缀:At、 Contro、Shit、Lock,并且它不区分大小写按键,即输入a和A是相同的键码 |
.time | 时间 |
.type | 事件类型 |
.widget | 触发事件的对应组件 |
.char | 字符 |
Event事件对象按键的详细信息说明如下
.keysym | .keycode | .keysym_num | 说明 |
---|---|---|---|
Alt_L | 64 | 65513 | 左边的【At】键 |
AIt_R | 113 | 65514 | 右边的【At】键 |
BackSpace | 22 | 65288 | 【 BackSpace】键 |
Cancel | 110 | 65387 | 【 Pause Break】键 |
F1~F11 | 67~77 | 65470~65480 | 功能键【F1】~【F11】 |
111 | 65377 | 打印屏幕键 |
from tkinter import *
tk = Tk()
def printkey(event):
print('按下了:'+event.char)
entry = Entry(tk)
entry.bind('' , printkey) # 绑定按键监听事件,监听任何按键
entry.pack()
tk.mainloop()
from tkinter import *
tk = Tk()
def leftClick(event):
print('(x,y):',event.x,event.y)
print('相对于屏幕左上角x轴,y轴:',event.x_root,event.y_root)
lab = Label(tk, text='x,y')
lab.pack()
lab.bind('' , leftClick)
tk.mainloop()