龙听期货论坛's Archiver

龙听 发表于 2024-3-31 21:46

Python的标准GUI库Tkinter开发基础 - Tkinter事件基础

在计算机系统中有很多种事件,如鼠标事件、键盘事件和窗口事件等。鼠标事件主要是指鼠标按键的按下、释放,鼠标滚轮的滚动,鼠标指针移进、移出组件等所触发的事件。键盘事件主要是指键的按下、释放等所触发的事件。窗口事件是指改变窗口大小、组件状态等所触发的事件。

在Tkinter库中,事件是指在各个组件上发生的各种鼠标事件和键盘事件。对于按钮组件、菜单组件来说,可以在创建组件时通过参数command指定其事件的处理函数。除组件所触发的事件之外,在创建右键弹出菜单时还需处理右击事件。类似的事件还有鼠标事件、键盘事件和窗口事件。

在Python程序的Tkinter库中,鼠标事件、键盘事件和窗口事件可以采用事件绑定的方法来处理消息。为了实现控件绑定功能,可以使用控件中的bind()方法实现,或者使用bind_class()方法实现类绑定,分别调用函数或者类来响应事件。bind_all()方法也可以绑定事件,bind_all()方法能够将所有的组件事件绑定到事件响应函数上。上述3个方法的具体语法格式如下。[code]bind(sequence, func, add)
bind_class( className, sequence, func, add)
bind_all (sequence, func, add)[/code]各个参数的具体说明如下。

func:表示所绑定的事件处理函数。
add:表示可选参数,为空字符或者“+”。
className:表示所绑定的类。
sequence:表示所绑定的事件,必须是以尖括号“<>”包围的字符串。
在Tkinter库中,常用的鼠标事件如下。

<Button-1>:表示按下鼠标左键,而<Button-2>表示按下鼠标中键,<Button-3>表示按下鼠标右键。
<ButtonPress-l>:表示按下鼠标左键,与<Button-l>相同。
<ButtonRelease-l>:表示释放鼠标左键。
<Bl-Motion>:表示按住鼠标左键并移动。
<Double-Button-l>:表示双击鼠标左键。
<Enter>:表示鼠标指针进入某一组件区域。
<Leave>:表示鼠标指针离开某一组件区域。
<MouseWheel>:表示鼠标滑轮滚动动作。

在上述鼠标事件中,数字“1”可以替换成2或3。其中数字“2”表示鼠标中键,数字“3”表示鼠标右键。例如,<B3-Motion>表示按住鼠标右键并移动,<Double-Button-2>表示双击鼠标中键等。

在Tkinter库中,常用的键盘事件如下。

<KeyPress-A>:表示按下A键,可用其他字母键代替。
<Alt-KeyPress-A>:表示同时按下Alt键和A键。
<Control-KeyPress-A>:表示同时按下Control键和A键。
<Shift-KeyPress-A>:表示同时按下Shift键和A键。
<Double-KeyPress-A>:表示快速地按两下A键。
<Lock-KeyPress-A>:表示先按下CapsLock键再按下A键。
在上述键盘事件中,还可以使用Alt键、Control键和Shift的组合键。例如<Alt-Control-Shift- KeyPress-B>表示同时按下Alt键、Control键、Shift键和B键。其中,KeyPress可以使用KeyRelease替换,表示当按键释放时触发事件。读者在此需要注意的是,输入的字母要区分大小写,如果使用<KeyPress-A>,则只有按下Shift键或者按下CapsLock键时才可以触发事件。

在Tkinter库中,常用的窗口事件如下。

Activate:当控件由不可用转为可用时触发。
Configure:当控件大小改变时触发。
Deactivate:当控件由可用转为不可用时触发。
Destroy:当控件被销毁时触发。
Expose:当控件从被遮挡状态中暴露出来时触发。
FocusIn:当控件获得焦点时触发。
FocusOut:当控件失去焦点时触发。
Map:当控件由隐藏状态变为显示状态时触发。
Property:当窗体的属性被删除或改变时触发。
Unmap:当控件由显示状态变为隐藏状态时触发。
Visibility:当控件变为可视状态时触发。

当把窗口中的事件绑定到函数时,如果触发该事件,则会调用所绑定的函数进行处理。触发事件后,系统将向该函数传递一个event对象的参数。正因为如此,应该将被绑定的响应事件函数定义成如下格式。[code]def function(event):
<语句>[/code]在上述格式中,event对象具有的属性信息如表4-9所示。

表4-9 event对象的属性信息

[img]http://p.algo2.net/2024/0331/e7de545b31ae3.png[/img]

实例文件zhuan.py演示了使用Tkinter创建一个“英尺/米”转换器的过程。[code]from tkinter import*
from tkinter import ttk
def calculate(*args):
try:
value =float(feet.get())
meters.set((0.3048* value *10000.0+0.5)/10000.0)
exceptValueError:
pass
root =Tk()
root.title("英尺转换米")
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
feet =StringVar()
meters =StringVar()
feet_entry = ttk.Entry(mainframe, width=7, textvariable=feet)
feet_entry.grid(column=2, row=1, sticky=(W, E))
ttk.Label(mainframe, textvariable=meters).grid(column=2, row=2, sticky=(W, E))
ttk.Button(mainframe, text="计算", command=calculate).grid(column=3, row=3, sticky=W)
ttk.Label(mainframe, text="英尺").grid(column=3, row=1, sticky=W)
ttk.Label(mainframe, text="相当于").grid(column=1, row=2, sticky=E)
ttk.Label(mainframe, text="米").grid(column=3, row=2, sticky=W)
for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5)
feet_entry.focus()
root.bind('<Return>', calculate)
root.mainloop()[/code]上述代码的实现流程如下。

1)导入了Tkinter所有的模块,这样可以直接使用Tkinter的所有功能,这是Tkinter的标准做法。然而,在后面导入ttk后,接下来要用到的组件前面都要加前缀。举个例子,直接调用“Entry”会调用Tkinter内部的模块。然而,我们需要的是ttk里的“Entry”,所以,要使用“ttk.Enter”,如你所见,许多函数在两者中都有。如果同时用到这两个模块,则需要根据整体代码选择使用哪个模块,让ttk的调用更加清晰,本书也会使用这种风格。

2)创建主窗口,设置窗口的标题为“英尺转换米”。然后创建一个frame控件,用户界面上的所有东西都包含在里面,并且放在主窗口中。columnconfigure”/“rowconfigure用于告诉Tk,如果调整主窗口的大小,frame空间的大小也随之调整。

3)创建3个主要的控件,一个用来输入英尺的文本框,一个用来表示转换成米后的结果的标签,一个用于执行计算的“计算”按钮。这3个控件都是窗口中“带主题”控件的类的实例。同时为它们设置一些选项,比如输入的宽度、按钮显示的文本等。输入框和标签都带了一个神秘的参数“textvariable”。如果仅创建控件,控件是不会自动显示在屏幕上的,因为Tk并不知道这些控件和其他控件的位置关系。那是“grid”部分要做的事情。还记得程序的网格布局吗?我们把每个控件放到对应的行或者列中,“sticky”选项指明控件在网格单元中的排列,采用的是指南针方向。所以“w”代表固定这个控件在左边的网格中,“we”代表固定这个控件在左边的网格和右边的网格之间。

4)创建3个静态标签,然后放在合适的网格位置中。在最后4行代码中,首先处理frame中的所有控件,并且在每个控件的四周添加一些空隙。可以在之前调用grid的时候做这些事,但上面这样做也是一个不错的选择。然后告诉Tk让输入框获取到焦点。这个方法可以让光标一开始就在输入框的位置,用户可以不用再单击了。最后告诉Tk,如果用户按下了Enter键,就执行计算,等同于用户单击“计算”按钮。[code]def calculate(*args):
try:
value =float(feet.get())
meters.set((0.3048* value *10000.0+0.5)/10000.0)
exceptValueError:
pass[/code]在上述代码中定义了计算过程,无论是按Enter键还是单击“计算”按钮,都会从文本框中获取英尺,转换成米,然后输出到标签中。执行“英尺转换米”的效果如图4-11所示。

[img]http://p.algo2.net/2024/0331/0ec9279215e5c.png[/img]

页: [1]