今天我们利用canvas绘制、删除图片的的函数,以及鼠标事件的绑定来制作一个简单的九宫格拼图游戏。
首先从网上下九张图,它们是把一张图分割成了九宫图,打乱后显示在canvas画布上。
接下来我们只要实现图片的选中与拖动即可,用到了鼠标左键、按下并拖动左键、鼠标右键和鼠标移动四个事件的绑定。
其他的并不难,直接看完整代码和注释吧:
from tkinter import * import tkinter as tk from PIL import Image, ImageTk import random a=0 #用来记录绘制的图片编号,其中1-9为初始的9张 List = [1,2,3,4,5,6,7,8,9] random.shuffle(List) #打乱图片顺序 root = Tk() root.title("拼图游戏") root.geometry("1400x690") canvas = Canvas(root,width=1400, height=690) canvas.pack() #获得鼠标位置 def callback(event): global x,y x = event.x y = event.y #删除刚绘制的图片 def delete(event): try: if a>14: #前九张和五条边界线不能删除 canvas.delete(a) except: return #根据鼠标位置,确定当前区域,即选中的图片编号 def pick(event): global a if x<=230 and y<=230: a=1 elif 230<x<=460 and y<=230: a=2 elif 460<x<=690 and y<=230: a=3 elif x<=230 and 230<y<=460: a=4 elif 230<x<=460 and 230<y<=460: a=5 elif 460<x<=690 and 230<y<=460: a=6 elif x<=230 and 460<y<=690: a=7 elif 230<x<=460 and 460<y<=690: a=8 elif 460<x<=690 and 460<y<=690: a=9 #删除并重新绘制选中的图片 def call(event): global a,aa if a>14: #原图和边界线不删除 canvas.delete(a) exec('canvas.create_image(x,y,image=var{})'.format(i)) a=aa+1 #记录新的图片编号,aa的初始值为14 aa+=1 #九张图片的位置,以图片中心点为基准 lc=[[115,115],[230+115,115],[460+115,115],[115,230+115],[230+115,230+115],[460+115,230+115],[115,460+115],[230+115,460+115],[460+115,460+115]] #绘制初始九张图 for j in range(1,10): load = Image.open("pt/%s.png"%List[j-1]) exec('var{}= ImageTk.PhotoImage(load)'.format(j)) #批量创建变量 exec('canvas.create_image(lc[j-1][0],lc[j-1][1],image=var{})'.format(j)) #绘制初始五条边界线 canvas.create_line(690,0,690,690) canvas.create_line(690,230,1400,230,fill="white") canvas.create_line(690,460,1400,460,fill="white") canvas.create_line(920,0,920,690,fill="white") aa=canvas.create_line(1150,0,1150,690,fill="white") #绑定鼠标事件 canvas.bind("<B1-Motion>",call) #拖动左键,移动图片 canvas.bind("<Button-1>",pick) #点击左键,确定图片编号 canvas.bind("<Button-3>",delete) #右键删除 root.bind("<Motion>",callback) #移动鼠标获取坐标 root.mainloop()
注意事项:
代码中的难点是如何动态创建变量。
exec('canvas.create_image(x,y,image=var{})'.format(i))
之所以必须动态创建,是因为用上面这句赋给image值的时候,传进来的变量不能在后续发生改变,否则就会显示不出图片。因此显示九张图,就得创建九个变量var1、var2……var9,而不能用同一个变量给image传值。为了简便,我们只能动态地创建变量和调用。
另外,注意call函数中,之所以通过aa来给a赋值,而不是直接用:
exec('a=canvas.create_image(x,y,image=var{})'.format(i))
原因在于,exec里面赋值语句是不生效的(我也不知道为啥),a不会在里面被赋值。