其实GUI程序是一种事件导向
的应用程序设计,事件的来源可能是用户单击鼠标、键盘输入或是Widget 状态改变。tkinter提供一些机制让我们可以针对这些事件做更进一步的处理,这些处理的方式称为事件处理程序
例子
:复习
import tkinterdef show(): label.config(text="Click")def oneVar(): if varOne.get(): label.config(text="One!!!") else: label.config(text="One")def twoVar(): if varTwo.get(): label.config(text="Two!!!") else: label.config(text="Two")root = tkinter.Tk()root.geometry("300x200")btu = tkinter.Button(root, text="Click", command=show)btu.pack(anchor=tkinter.W)varOne = tkinter.BooleanVar()cbnOne = tkinter.Checkbutton(root, text="One", variable=varOne, command=oneVar)cbnOne.pack(anchor=tkinter.W)varTwo = tkinter.BooleanVar()cbnTwo = tkinter.Checkbutton(root, text="Two", variable=varTwo, command=twoVar)cbnTwo.pack(anchor=tkinter.W)label = tkinter.Label(root, bg="lightgreen", fg="red", height=2, width=12, font="Times 16 bold")label.pack()root.mainloop()123456789101112131415161718192021222324252627282930313233343536
运行结果:
我们通过command=show
,来设计show函数,这个show函数就是事件处理程序
语法格式如下
widget.bind(event, handler)1
参数:
widget:事件的来源,可以是root窗口对象,或是任意的Widget控件,例如,功能按钮,选项按钮,复选框等等
第一个参数:evevt
,事件的参数,下面具体说明
第二个参数:handler
,事件处理程序,也就是根据event来触发的函数
下面我们来看具体参数
鼠标事件 | 说明 |
---|---|
<Button-1> | 鼠标左键单击 |
<Button-2> | 鼠标中键单击 |
<Button-3> | 鼠标右键单击 |
<Button-4> | 鼠标滑轮向上滚动(Linux) |
<Button-5> | 鼠标滑轮向下滚动(Linux) |
<B1-Motion> | 鼠标左键拖动 |
<B2-Motion> | 鼠标中键拖动 |
<B3-Motion> | 鼠标右键拖动 |
<ButtonRelease-1> | 鼠标左键释放 |
<ButtonRelease-2> | 鼠标中键释放 |
<ButtonRelease-3> | 鼠标右键释放 |
<Double-Button-1> | 鼠标左键双击 |
<Double-Button-2> | 鼠标中键双击 |
<Double-Button-3> | 鼠标右键双击 |
<Enter> | 鼠标指针进入控件 |
<Leave> | 鼠标指针离开控件 |
上述的参数,执行后鼠标光标相对控件的位置会被存入事件对象的x和y变量中,所以这就是为什么我们在handler函数中要加入event
形参,这个是必须要传的
注:
<1> = <Button-1> =<ButtonPress-1><2> = <Button-2> = <ButtonPress-2><3> = <Button-3> =<ButtonPress-3>123
这是通用的,<>
不能省略
绑定的方式
button.bind("<Button-1>", handler)1
例子
:鼠标移动,右下方看到鼠标目前的坐标
import tkinterdef moving(event): # .x_root, .y_root是相对于整个屏幕 # 获取x轴坐标(相对于窗口) x = event.x # 获取y轴坐标(相对于窗口) y = event.y textvar = "坐标 : x:%r y:%r" % (x, y) var.set(textvar)root = tkinter.Tk()root.geometry("300x200")x, y = 0, 0var = tkinter.StringVar()text = "坐标 : x:%r y:%r" % (x, y)var.set(text)label = tkinter.Label(root, textvariable=var)label.pack(anchor=tkinter.S, side=tkinter.RIGHT, padx=10, pady=10)# 事件是鼠标移动,执行moving函数root.bind("<Motion>", moving)root.mainloop()12345678910111213141516171819202122232425
运行结果:
moving(event)中的event
是可以自定义的,但是不能没有
键盘事件 | 说明 |
---|---|
<Return> | 回车 |
<Cancel> | Break键 |
<BackSpace> | BackSpace键 |
<Tab> | Tab键 |
<Shift_L> | 左Shift键 |
<Alt_L> | 左Alt键 |
<Control_L> | 左Control键 |
<Shift_R> | 右Shift键 |
<Alt_R> | 右Alt键 |
<Control_R> | 右Control键 |
<Pause> | Pause键 |
<Caps_Lock> | Caps_Lock键 |
<Escape> | Escapel键,俗称Esc |
<Prior> | PageUp键 |
<Next> | PageDown键 |
<End> | End键 |
<Home> | Home键 |
<Left> | 左箭头 |
<Up> | 上箭头 |
<Right> | 右箭头 |
<Down> | 下箭头 |
<Print> | Print Screen |
<Insert> | Insert键 |
<Delete> | Delete键 |
<F1> | F1键 |
<F2> | F2键 |
<F3> | F3键 |
<F4> | F4键 |
<F5> | F5键 |
<F6> | F6键 |
<F7> | F7键 |
<F8> | F8键 |
<F9> | F9键 |
<F10> | F10键 |
<F11> | F11键 |
<F12> | F12键 |
<Num_Lock> | Num_Lock键 |
<Scroll_Lock> | Scroll_Lock键 |
<plus> | 小键盘上的 + 键 |
<minus> | 小键盘上的 - 键 |
<asterisk> | 小键盘上的 * 键 |
<slash> | 小键盘上的 / 键 |
<key> | 任意键 |
注:
<key> = <KeyPress> = <KeyRelease>1
例子
:当我们按下Tab
时,tkinter做出响应
import tkinterdef tab(event):# keysym 键盘事件对应的字符串 print(f"按下了{event.keysym}键")root = tkinter.Tk()root.geometry("100x80")root.bind("<Tab>", tab)root.mainloop()1234567891011
运行结果:
字符 | 说明 |
---|---|
<a> | 字母a |
<b> | 字母b |
此处省略剩下的24个字母 | 此处省略剩下的24个字母 |
<1> | 数字1 |
<2> | 数字2 |
此处省略剩下的8个数字 | 此处省略剩下的8个数字 |
<A> | 按键shift+a或者字母大写A |
<B> | 按键shift+b或者字母大写B |
此处省略剩下的24个大写字母 | 此处省略剩下的24个写字母 |
注:
<a> = <Key-a> = <KeyPress-a> = <KeyRelease-a>1
例子
:当我们按下a
时,tkinter做出响应
import tkinterdef tab(event): print(f"按下了{event.keysym}键")root = tkinter.Tk()root.geometry("100x80")root.bind("<a>", tab)root.mainloop()12345678910
运行结果:
组合键 | 说明 |
---|---|
<Shift-Home> | Shift+Home |
<Alt-Home> | Alt+Home |
<Control-Home> | Ctrl+Home |
<Control-A> | Ctrl+shift+a |
注:
组合键不止这些,可以自由组合
例子
:当我们按下Alt+Home
时,tkinter做出响应
import tkinterdef tab(event): print(f"按下了home键")root = tkinter.Tk()root.geometry("100x80")root.bind("<Alt-Home>", tab)root.mainloop()12345678910
运行结果:
窗体事件 | 说明 |
---|---|
<Configure> | 改变大小或位置 |
<Visibility> | 当组件变为可视状态时触发 |
<Unmap> | 当组件由显示状态变为隐藏状态时触发 |
<Map> | 当组件由隐藏状态变为显示状态时触发 |
<Expose> | 当组件从原本被其他组件遮盖的状态中暴漏出来时触发 |
<FocusIn> | 组件获得焦点时触发 |
<FocusOut> | 组件失去焦点时触发 |
<Circulate> | 当窗体由于系统协议要求在堆栈中置顶或压底时触发 |
<Colormap> | 当窗体的颜色或外貌改变时触发,Tk中忽略此细则 |
<Property> | 当窗体的属性被删除或改变时触发,属于TK的核心 |
<Destroy> | 当组件被销毁时触发 |
<Activate> | 与组件选项中的state项有关,表示组件由不可用变为可用时触发 |
<Deactiavte> | 与组件选项中的state项有关,表示组件由可用变为不可用时候触发 |
例子
:获得焦点与失去焦点,由Tab键进行切换
import tkinterdef a(event): label.config(text="获取焦点")def b(event): label.config(text="失去焦点")root = tkinter.Tk()root.geometry("300x200")btu = tkinter.Button(root, text="Click")btu.pack(anchor=tkinter.W)btu.bind("<FocusIn>", a)btu.bind("<FocusOut>", b)btu1 = tkinter.Button(root, text="Other")btu1.pack(anchor=tkinter.W)label = tkinter.Label(root, bg="lightgreen", fg="red", height=2, width=12, font="Times 16 bold")label.pack()root.mainloop()123456789101112131415161718192021222324
运行结果:
例子
:组件由隐藏状态变为显示状态,显示状态变为隐藏状态
from tkinter import *def show(event): b2.config(bg="lightyellow") # SystemButtonFace 默认的颜色,就是那个灰色 b1.config(bg="SystemButtonFace")def Unshow(event): b1.config(bg="lightblue") b2.config(bg="SystemButtonFace")root = Tk()l1 = Label(root, text='pack_forget')b3 = Button(root, text='按钮')b3.bind("<Unmap>", Unshow)b3.bind("<Map>", show)# pack_forget 不显示b1 = Button(root, text='隐藏', command=b3.pack_forget)b2 = Button(root, text='显示', command=b3.pack)l1.pack(fill=X)b1.pack(fill=X)b2.pack(fill=X)b3.pack()root.mainloop()12345678910111213141516171819202122232425262728
运行结果:
Event | 说明 |
---|---|
widget | 事件被触发的控件 |
.x, .y | 鼠标距离窗体左上角的位置(坐标) |
.x_root, .y_root | 鼠标距离屏幕左上角的位置(坐标) |
.char | 键盘事件对应的字符代码 |
.keysym | 键盘事件对应的字符串 |
.keycode | 键盘事件对应的按键码 |
.num | 鼠标事件对应的按键码 |
.width, .height | 控件的新大小 |
.type | 事件类型 |
例子
:键盘输入,tkinter响应字符串和按键码(ASCII)
import tkinterdef show(event): print(f"{event.keysym}对应的ASCII码:{event.keycode}")win = tkinter.Tk()win.geometry("150x100")win.bind("<Key>", show)win.mainloop()12345678910
运行结果:
每套键盘可能对应的ASCII都不同,所以在这里我并没有写明每个字母、字符、数字的ASCII值,即使写了可能也与大家的ASCII值不同,怎样得知自己键盘的ASCII值呢?
上述的方法获取是最好验证的,请参照Event的基本应用
中的例子
取消绑定xx
的方法如下:
# <xxx>是绑定方式xx.unbind("<xxx>")12
例子
:
import tkinterdef show(event): label.config(text="ForPython!")def choose(x): if var.get(): x.bind("<Button-1>", show) else: label.config(text="") x.unbind("<Button-1>")root = tkinter.Tk()root.geometry("300x200")btu = tkinter.Button(root, text="Click")btu.pack(anchor=tkinter.W)var = tkinter.BooleanVar()cbut = tkinter.Checkbutton(root, text="bind/unbind", variable=var, command=lambda: choose(btu))cbut.pack(anchor=tkinter.W)label = tkinter.Label(root, bg="lightgreen", fg="red", height=2, width=12, font="Times 16 bold")label.pack()root.mainloop()123456789101112131415161718192021222324252627
运行结果:
使用bind()
方法可以绑定一个事件处理程序,tkinter也允许我们执行一个事件绑定多个事件处理程序,同样使用bind()
方法,但是新增加的时间处理程序需要在bind()方法内增加参数add = "+"
例子
:
import tkinterdef show(): print("???")def shower(event): print("!!!")root = tkinter.Tk()button = tkinter.Button(root, text="Click", command=show)button.pack()button.bind("<1>", shower, add="+")root.mainloop()1234567891011121314151617
程序会先执行bind()
绑定的程序,然后再执行Button()
内command
指定的程序
Protocols 可以翻译为通信协议
,在tkinter内可以解释为窗口管理程序
(Windows Manager)与应用程序
(Application)之间的通信协议
。tkinter也支持使用绑定概念更改此通信协议
例子
:退出程序询问是否要退出
import tkinterfrom tkinter import messageboxdef show(): res = messagebox.askokcancel("提示", "请问您确定要退出吗?") if res: root.destroy() else: returnroot = tkinter.Tk()root.protocol("WM_DELETE_WINDOW", show)root.mainloop()12345678910111213141516
运行结果:
谢谢观看,笔者会持续更新,如有错误或者建议,请私信我