数字华容道-将显示数字单击数字事件绑定及事件处理函数封装在python类中以简化编程
Posted geng_zhaoying
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数字华容道-将显示数字单击数字事件绑定及事件处理函数封装在python类中以简化编程相关的知识,希望对你有一定的参考价值。
在博文“数字华容道游戏_用Python tkinter Canvas实现”一文中,游戏用Canvas的text实例显示数字。text实例显示数字不同,其属性tag值也不同,根据text实例属性tag值,就能找到相应数字(text实例)。为了使鼠标单击数字事件处理函数知道要移动那个数字,必须用参数将被点击数字(text实例)tag值传递给该事件处理函数。采用的方法是在Canvas中每创建一个text实例,都令其有不同tag值,同时为该text实例创建一个单击数字事件函数,该函数有参数nTag其默认值是这个text实例的tag值。单击某数字,这个text实例(数字)用自己的事件函数响应,该事件函数找到其参数nTag的默认值指定的text实例(数字),完成对被点击数字的移动和输赢判断。这样每一个text实例都有一个事件函数,占用较多资源。
本文所用方法是:创建一个新类能显示数字华容道中数字并能操作数字,新类在canvas上创建text实例显示数字。text实例显示数字不同,其属性tag值也不同,根据text实例属性tag值,就能找到显示相应数字的text实例。类要保存必要数据,包括用实例变量self.tagN保存显示不同数字的text实例的tag值。在类中绑定单击数字(text实例)事件处理函数为类实例方法,使事件处理函数能直接访问类中数据。单击某数字(text实例),text实例用事件处理函数响应,事件处理函数根据实例变量self.tagN,找到被点击数字(text实例),完成对被点击数字的移动和输赢判断,从而简化编程。这样就不必为了将text实例tag值传递给鼠标单击数字事件处理函数,象上节那样为每一个text实例创建一个事件处理函数,使程序变得复杂,占用较多资源。实现的框架如下(不能运行只是用来说明问题):
class numSquare():
X0=Y0=0 #类变量,空位所在位置的坐标(X0,Y0),所有类实例共用
def __init__(self,x,y,n): #构造函数
self.tagN="A"+n #保存下句在Canvas中创建的text实例的tag值
#在Canvas中创建text实例显示数字,text实例显示数字不同,其属性tag值也不同
w.create_text(x,y,text=n,fill="red",tag=self.tagN,font=("Arial",40))
#绑定单击数字(text实例其tag=self.tagN)事件函数为类实例方法self.leftClick
w.tag_bind(self.tagN,'<Button-1>',self.leftClick)
def leftClick(self,event): #类实例方法
x,y=w.coords(self.tagN)#得到被点击的数字所在位置坐标
w.move(self.tagN,numSquare.X0-x,numSquare.Y0-y) #移动数字到空位
w=tk.Canvas(root,width=300,height=260,background="white")#建立Canvas对象
w.pack()
numSquare(0,0,5) #创建numSquare类实例,参数对应类构造函数的参数x,y,n
创建numSquare实例将首先调用该类构造函数,并将numSquare类的实例ID传递给self。在构造函数中,首先用实例变量self.tagN保存将要建立的text实例的tag值,然后在Canvas中建立text实例用来显示数字,最后使用self.tag将相应的text实例和鼠标左键单击事件绑定,事件处理函数leftClick(self,event)是类的实例方法,可访问numSquare类的self.tag,通过self.tag可以访问这个text实例的所有数据。我们不能错误地认为,每创建一个numSquare实例,就要创建一个事件处理函数leftClick。实际情况是无论有多少个numSquare实例,leftClick方法只有一个,当然不同类实例的实例数据是不同的。本例所有numSquare实例中text实例的事件处理函数都是这个唯一的leftClick实例方法。当单击某数字(text实例)后,这个text实例响应鼠标左键单击事件,其事件处理函数leftClick从包含该数字(text实例)的numSquare实例中得到self.tagN,根据self.tagN找到被点击数字(text实例),从而完成对被点击数字(text实例)的移动和输赢判断。完整程序如下:
import tkinter as tk
import random
class numSquare():
X0=Y0=0 #类变量,空位所在位置的坐标(X0,Y0),所有类实例共用
gameOver=False
canvasID=0
labelID=0
def __init__(self,x,y,n): #构造函数
self.tagN="A"+n #保存下句在Canvas中创建的text实例的tag值
numSquare.canvasID.create_text(x,y,text=n,fill="red",tag=self.tagN,font=("Arial",40))
numSquare.canvasID.tag_bind(self.tagN,'<Button-1>',self.leftClick) #绑定左键单击事件
def leftClick(self,event): #类实例方法
x,y=numSquare.canvasID.coords(self.tagN) #得到被点击的数字所在位置的坐标
#判断被单击数字是否和空白处相邻并且游戏未结束
if abs(x-numSquare.X0)+abs(y-numSquare.Y0)==60 and numSquare.gameOver==False:
numSquare.canvasID.move(self.tagN,numSquare.X0-x,numSquare.Y0-y) #移动数字到空白处
numSquare.X0,numSquare.Y0=x,y #记录新空白处位置坐标
numbers=list('087654321')
for y in range(90,270,60): #y为Canvas上数字的y坐标,90,150,210,即行坐标
for x in range(90,270,60): #x为Canvas上数字的x坐标,90,150,210,即列坐标
m=numbers.pop()
if m!= '0': #如m!= '0',8个数字还未检查完
#tag='A1'对象显示1,在(90,90)位置正确,tag='A2'字符显示2,在(150,90)处正确等等
if [x,y]!=numSquare.canvasID.coords("A"+m):#如相应字符对象位置不正确,玩家未赢
return
else: #如m=='0',8个数字所在位置正确,玩家赢了
numSquare.gameOver=True
numSquare.labelID['text']="你赢了"
root = tk.Tk() #初始化窗口
root.title('数字华容道_用类实现') #窗口标题
root.geometry("300x260+200+20") #窗口宽300,高=260,窗口左上点离屏幕左边界200,离屏幕上边界距离20。
root.resizable(width=False,height=False) #设置窗口是否可变,这里宽不可变,高不可变,默认为True
w = tk.Canvas(root, width = 300, height = 260, background = "white") #建立Canvas对象
w.pack()
numSquare.canvasID=w
numbers=list('123456780')
random.shuffle(numbers) #使列表数字和空白随机排列
numSquare.labelID=tk.Label(numSquare.canvasID,text='单击数字移动方块',fg='red',font=("Arial",15))
numSquare.labelID.place(x=20,y=10,width=250,height=40)
for x in range(60,300,60): #画棋盘4条竖线,x为Canvas的x坐标
w.create_line(x,60,x,240,fill = "black",width = 3)
for y in range(60,300,60): #画棋盘4条横线,y为Canvas的y坐标
w.create_line(60,y,240,y,fill = "black",width = 3)
for y in range(90,270,60): #y为Canvas上数字的y坐标,90,150,210,即行坐标
for x in range(90,270,60): #x为Canvas上数字的x坐标,90,150,210,即列坐标
n=numbers.pop()
if n!='0': #如n!='0',建立8个数字对象
numSquare(x,y,n)
else: #n=0,代表空白,记住无数字的空位的Canvas坐标(x,y)
numSquare.X0,numSquare.Y0=x,y
root.mainloop()
以上是关于数字华容道-将显示数字单击数字事件绑定及事件处理函数封装在python类中以简化编程的主要内容,如果未能解决你的问题,请参考以下文章