在最近使用的对象上调用函数?

Call function on most recently used object?

所以,我正在使用 tkinter 为 Tic Tac Toe 编写一个图形用户界面,并且我正在尝试实现一个 "Undo" 功能。

我有一个 class "Square",它是 canvas 的子 class,具有绘制零、交叉或清除自身的方法。 "Undo" 函数应该计算出最近播放的方块是哪个,并调用它的 clear 方法。

我有一个所有移动的全局列表,称为 "notation",所以如果我能够对 notation.pop() 返回的对象调用清除函数,这应该可以工作。

这是实现它的合理方式吗?我该怎么做?

下面是我的代码和我当前的 "Undo" 按钮,它被硬编码为只能撤消 C,中央广场。

import tkinter as tk

# notation is a list containing all moves made
notation = []

# This class defines a Square, just a clickable canvas which shows a nought or cross when clicked
class Square(tk.Canvas):
    def __init__(self, name, master=None, width=None, height=None):
        super().__init__(master, width=width, height=height)
        self.bind("<Button-1>", self.tic)
        self.bind("<Button-2>", self.tac)
        self.free=True
        self.name=name


    def tic(self, event):
        """"This will draw a cross on the selected Square."""
        if self.free:
            self.create_line(30, 30, 170, 170)
            self.create_line(30, 170, 170, 30)
            self.free = False
            global notation
            notation.append(self.name)
            print(notation)

    def tac(self, event):
        """"This will draw a nought on the selected Square."""
        if self.free:
            self.create_oval(30, 30, 170, 170)
            self.free = False
            global notation
            notation.append(self.name)
            print(notation)

    def clear(self):
        """"This will clear the selected Square."""
        if not self.free:
            self.delete("all")
            self.free = True
            global notation
            notation.pop()
            print(notation)

root = tk.Tk()
root.title("Tic Tac Toe")

NW = Square("NW", master=root, width=200, height=200)
NW.grid(row=0, column=0)

N = Square("N", master=root, width=200, height=200)
N.grid(row=0, column=1)

NE = Square("NE", master=root, width=200, height=200)
NE.grid(row=0, column=2)

W = Square("W", master=root, width=200, height=200)
W.grid(row=1, column=0)

C = Square("C", master=root, width=200, height=200)
C.grid(row=1, column=1)

E = Square("E", master=root, width=200, height=200)
E.grid(row=1, column=2)

SW = Square("SW", master=root, width=200, height=200)
SW.grid(row=2, column=0)

S = Square("S", master=root, width=200, height=200)
S.grid(row=2, column=1)

SE = Square("SE", master=root, width=200, height=200)
SE.grid(row=2, column=2)

# Creating File Menu
menu = tk.Menu(root)
root.config(menu=menu)

fileMenu = tk.Menu(menu)
menu.add_cascade(label="File", menu=fileMenu)
fileMenu.add_command(label="Undo", command=lambda: C.clear())

root.mainloop()

你的想法有点对。您需要做的是将整个实例添加到符号列表中,然后当您弹出最后一个时,您可以调用它的清除方法:

def tac(self, event):
        notation.append(self) # add this instance to the list

...
fileMenu.add_command(label="Undo", command=lambda: notation.pop().clear())

并去掉 clear 方法中的 pop

编辑:您可能知道,全局变量不好。在这种情况下,我们使用 class 变量,这些变量基本上是 class 的所有实例都可以访问的实例变量。 class 变量是在方法之外定义的,没有 "self." 前缀,但是您需要使用 class 名称或 "self" 来访问它(例如,在您的情况下从 class 内部使用 self.notaion 或从外部使用 Square.notation 访问它)。我们还将使用 class 方法来操作它们。看看你能不能理解这个:

import tkinter as tk

class Square(tk.Canvas):
    notation = [] # this is a class variable

    def __init__(self, name, master=None, width=None, height=None):
        super().__init__(master, width=width, height=height)
        self.bind("<Button-1>", self.tic)
        self.bind("<Button-2>", self.tac)
        self.free=True
        self.name=name

    def tic(self, event):
        """"This will draw a cross on the selected Square."""
        if self.free:
            self.create_line(30, 30, 170, 170)
            self.create_line(30, 170, 170, 30)
            self.free = False
            self.notation.append(self)
            self.print()

    def tac(self, event):
        """"This will draw a nought on the selected Square."""
        if self.free:
            self.create_oval(30, 30, 170, 170)
            self.free = False
            self.notation.append(self)
            self.print()

    def clear(self):
        """"This will clear the selected Square."""
        if not self.free:
            self.delete("all")
            self.free = True
            self.print()

    @classmethod
    def undo(cls):
        cls.notation.pop().clear()

    @classmethod
    def print(cls):
        print('History:', *[s.name for s in cls.notation])

root = tk.Tk()
root.title("Tic Tac Toe")
for i, name in enumerate('NW N NE W C E SW S SE'.split()):
    s = Square(name, master=root, width=200, height=200)
    row, column = divmod(i, 3)
    s.grid(row=row, column=column)

# Creating File Menu
menu = tk.Menu(root)
root.config(menu=menu)

fileMenu = tk.Menu(menu)
menu.add_cascade(label="File", menu=fileMenu)
fileMenu.add_command(label="Undo", command=Square.undo)

root.mainloop()

我也去掉了你的重复。记住 DRY ... 如果您是 copy/pasting 代码,那么您正在执行计算机的工作。