今天我們利用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不會在里面被賦值。