派生类中事件绑定的事件处理函数是类实例方法使其能访问父类和派生类所有数据
Posted geng_zhaoying
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了派生类中事件绑定的事件处理函数是类实例方法使其能访问父类和派生类所有数据相关的知识,希望对你有一定的参考价值。
如Button类要响应鼠标右键单击事件,并希望其事件处理函数能处理Button类所有数据,本文给出一种解决方法。该方法是从Button类派生一个新类,在新类中绑定的鼠标右键单击事件处理函数是新类的实例方法,即当鼠标右键单击这个新类按钮后,系统发出鼠标右键单击事件,程序用事件处理函数响应这个事件,即调用这个实例方法可访问新类(包括父类)所有数据,完成所需功能。实现的框架如下(不能运行只是用来说明问题):
class MyClass(Button): #类定义,不能运行只是用来说明问题
def __init__(self): #构造函数
...
self.bind('<Button-3>',self.do_job2) #事件绑定
def do_job2(self,event): #实例方法,self为MyClass实例
...
当创建MyClass实例时,将首先调用该类构造函数,并将MyClass类的实例ID传递给self。在构造函数中,语句self.bind将使MyClass这个实例响应鼠标右键单击事件,事件处理函数是MyClass类的实例方法do_job2(self,event)。注意,这个函数的参数self是MyClass类的实例ID,通过它可以访问MyClass类的这个实例的所有(包括父类)数据,第2个参数是传递事件的信息,例如本例,可得到鼠标单击时所在位置坐标等。我们不能错误地认为,每创建一个MyClass类的实例,就创建一个事件处理函数do_job2方法。实际情况是无论MyClass类有多少个实例,do_job2方法只有一个,当然每个实例的数据是不同的。本例MyClass类的所有实例的事件处理函数都是这个唯一的do_job2方法,当某个MyClass类实例按钮被鼠标右击,将把这个MyClass类实例按钮的ID传给函数do_job2的参数self,这时do_job2方法可通过self访问的这个所有(包括父类)数据,完成右击这个按钮所应完成的功能。
在创建MyClass类实例时,也可以指定外部函数为按钮事件处理函数,并将类属性值传递给外部函数,实现的框架如下(不能运行只是用来说明问题):
class MyClass(Button): #类定义,不能运行只是用来说明问题
def __init__(self,command=None): #构造函数
...
self.x=1
self.command=command
self.bind('<Button-1>',self.do_job2) #事件绑定
def do_job2(self,event): #实例函数
self.command(event,self.x)
def do_job4(evt,x):
a=x
myClass=MyClass(command=do_job4) #创建MyClass类实例myClass
下面用一个实例进一步详细说明这种方法。该例子有4个无标题按钮,是从Button类派生的MyButton类实例,其编号左上角为00、右上角为01、左下角为10、右下角为11。用鼠标左键单击、右键单击或双击按钮,将在Label组件上显示鼠标左(右)键单(双)击()+编号。还增加了一个Button类实例按钮,其标题是:Button类不受影响,无论是用鼠标单击、右键单击或双击这个按钮,都不会改变label的显示内容。运行效果图如下:
该例实际介绍了3种绑定事件的方法,加上博文“python3.8的tkinter按钮事件函数实现多个参数另一种方法”或“数字华容道游戏_用Python tkinter Canvas实现”介绍的绑定事件方法,前后共介绍了4种事件处理函数实现多个参数的绑定事件方法。本例具体代码如下:
from tkinter import *
class MyButton(Button):
LabelID=0#类变量,无论有多少个类实例,是唯一的,所有类实例共用。使用方法是:类名.类变量名
def __init__(self,master,command,row, col,f1): #构造函数,下句调用基类的构造函数
super().__init__(master=master,command=command,bg="Silver",fg='red',font=("Arial",20))
self.row = row #按钮所在位置的行数
self.col = col #按钮所在位置的列数
self.f1=f1 #记录参数f1传递的外部函数的引用地址(ID)
#绑定鼠标右键单击事件的事件函数,右击该按钮后自动调用self.do_job2,self自动传递给函数do_job2第一个参数
self.bind('<Button-3>',self.do_job2)
self.bind('<Double-Button-3>',self.do_job1) #绑定鼠标右键双击事件的事件函数
def do_job1(self,event): #鼠标右键双击击事件函数
MyButton.LabelID['text']='鼠标右键双击'+ str(self.row)+str(self.col) #注意如何使用类变量
def do_job2(self,event): #鼠标右键单击事件函数
self.f1(event,self.row,self.col) #调用外部函数,参数为:事件参数,该按钮的行号,列号
def do_job(x,y): #鼠标左键单击事件函数,参数是lambda表达式传递的行列号
label1['text']='鼠标左键单击'+str(x)+str(y)
def do_job4(evt,x,y): #被MyButton类函数do_job2调用的函数,x,y是函数do_job2传递的行列号,
label1['text']='鼠标右键单击'+str(x)+str(y)
root = Tk()
root.title('在类中绑定事件')
root.geometry("350x200")
root.resizable(width=False,height=False)
label1=Label(root,text='鼠标左键单击,右键单击和双击各方块',bd='5',fg='red',font=("Arial",15))
label1.place(x=3,y=5,width=350,height=30)
MyButton.LabelID=label1 #注意如何为类变量赋值
buttons={} #字典记录按钮的引用地址,键值是行列号
for m in range(2):
for n in range(2): #注意下句如何传递行号、列号和外部函数do_job4
b1=MyButton(root,command=lambda x=m,y=n:do_job(x,y),row=m,col=n,f1=do_job4)
b1.place(x=150+n*32,y=45+m*32,width=30,height=30)
buttons[m,n]=b1
b2=Button(root,text='Button类不受影响') #Button类不受影响,不响应鼠标所有事件
b2.place(x=85+n*32,y=100+m*32,width=120,height=30)
root.mainloop()
以上是关于派生类中事件绑定的事件处理函数是类实例方法使其能访问父类和派生类所有数据的主要内容,如果未能解决你的问题,请参考以下文章