记忆对对碰

为了巩固GUI,把上星期在coursera上课的作业改成Tkinter版
完成课程miniproject所用的module,是simplegui,代码.py), 需要用这个在线的CLI来运行
simplegui版的效果如下

下面进入Tkinter版的实现过程

源代码

这种桌面的GUI,虽然simplegui和tkinter不同,肯定也都是跟tk相关,于是在github上查找了下源代码,果然simplegui只是像tkinter的变种,前者能把后者更explicitly地“翻译”过来,便于理解。研究完之后发现,与其这样翻译,还不如直接用tkinter再实现一遍这个游戏

框架

from Tkinter import *
import random

def new_game():
    pass    
def draw_canvas():
    pass
def mouseclick():
    pass
root = Tk()

canvas_frame = Frame(root, width = 800, height = 100, bg = 'yellow')
canvas_frame.grid(row=0, column=1, rowspan=2, padx=5, pady=5)

new_game()

root.mainloop()

创建一个Frame,三个函数,分别是用来初始化的函数,处理canvas的函数,以及处理鼠标信息的函数

在Frame上创建一个canvas, 在canvas上随机输入16个预制数字

def new_game():
    list1 = range(0,8)
    list2 = range(0,8)  
    global m_list
    m_list = list1 + list2
    random.shuffle(m_list)

    draw_canvas()

def draw_canvas():
    cv = Canvas(canvas_frame, width = 800, height = 100, bg = 'white')
    cv.grid(row=0, column=1, rowspan=2, padx=5, pady=5)

    n = 30
    for numb in m_list:
        cv.create_text((n, 50), font = 'Verdana 35',text=str(numb))
        n += 49

其中create_text中的参数(n, 50)是输入数字的坐标,n之所以选30是因为和字号35配合,刚好能在canvas上把16个数字平均分开,以便之后用来翻牌的程序正常的显示出完整的数字。

添加翻牌程序

def new_game():
    list1 = range(0,8)
    list2 = range(0,8)  
    global m_list
    m_list = list1 + list2
    random.shuffle(m_list)
    global expo_list
    expo_list = [False] * 16

    draw_canvas()

def draw_canvas():
    cv = Canvas(canvas_frame, width = 800, height = 100, bg = 'white')
    cv.grid(row=0, column=1, rowspan=2, padx=5, pady=5)

    n = 30
    for numb in m_list:
        cv.create_text((n, 50), font = 'Verdana 35',text=str(numb))
        n += 49

    for i in range(16):
        if expo_list[i] == False:       
            cv.create_rectangle(i * 50, 0, (i * 50)+ 49, 100,width=1,outline='Red',fill = 'Green')

new_game()下添加一个global list,expo_list, 当它是False的时候,其对应位置的数字上会用绿色的矩形(也就是所谓牌的背面),其大小就由create_rectangle来控制。
i 50, 0, (i 50) + 49, 100分别是矩形的左上,左下,↘️,↗️,四个点,i对应的牌的号码。

鼠标点击的坐标处理

def draw_canvas():
    cv = Canvas(canvas_frame, width = 800, height = 100, bg = 'white')
    cv.grid(row=0, column=1, rowspan=2, padx=5, pady=5)

    n = 30
    for numb in m_list:
        cv.create_text((n, 50), font = 'Verdana 35',text=str(numb))
        n += 49

    for i in range(16):
        if expo_list[i] == False:       
            cv.create_rectangle(i * 50, 0, (i * 50)+ 49, 100,width=1,outline='Red',fill = 'Green')
    cv.bind("<Button-1>", mouseclick)

def mouseclick(event):
    global state, no_1, no_2
    pos = event.x
    no_i = pos // 50
    if expo_list[no_i] != True:
        if state == 0:
            no_1 = no_i
            expo_list[no_1] = True
            state = 1
        elif state == 1:
            no_2 = no_i
            expo_list[no_2] = True
            state =2
        else:
            if m_list[no_1] != m_list[no_2]:
                expo_list[no_1] = False
                expo_list[no_2] = False
                no_1 = no_i
                expo_list[no_1] = True
                state = 1
            else:
                no_1 = no_i
                expo_list[no_1] = True
                state = 1
    draw_canvas()

cv.bind("< Button-1 >", mouseclick):当有鼠标左键点击时,触发mouseclick函数,并传入event数据。
state, no_1, no_2,都是要重复使用并且每次点击鼠标都有可能更新的参数,所以要在初始化函数New_game先声明出来,然后再在mouseclick中引用。
pos = event.x <- 取横坐标

逻辑:先判断此牌是否被掀开,没被掀开执行 -> state = 0 时,初始状态,0张牌被翻到正面,翻开一张牌记作no1;state = 1 时,一张牌已被翻开,再翻开一张牌,记作no2;state = 2 时,2张牌已被翻开,比较这两张牌的数字,如果不相等,则把两个牌翻回去,新的一张牌再翻成正面,如果相同,则直接执行新番一张牌。