在调用.after()方法后取消事件?

时间:2013-10-20 02:31:00

标签: python events canvas tkinter

我正在使用画布小部件用python tkinter模块编写一个小游戏。 有一个人,只是一个球,每10秒产生一次炸弹。 炸弹生成3秒后,它开始一个“爆炸”过程,我在self.bomb对象上调用另外4个方法来“动画”它爆炸。

游戏的目的是试图“解除”炸弹。我想出了一些有趣的碰撞检测功能。一旦检测到碰撞,使用以下方法将炸弹从画布上清除:

self.canvas.delete(self.bomb)

然而,即使我已经“解除”了炸弹,下面的炸弹变大和变色(爆炸)的动画仍然会发生。这是因为我原来的炸弹叫:

self.parent.after(3000, self.explode_first)

...我已经链接了3个“爆炸”函数,所有函数都使用.after()方法进行绑定和调用。

我试图通过在.after()中调用的每个方法中插入条件来避免这个问题,就像布尔一样;

if self.bomb # if there's a bomb on the canvas,
     self.parent.after(125, self.explode_second) # and explode third and so on

哪个不行。我希望能够“取消”使用after方法创建的tkinter队列的事件,但这里是踢球者。我不能(不能)杀死所有事件,只是画布上的事件。如果可能的话,我还有其他活动要完整保留。

有办法做到这一点吗?如果没有,欢迎提供有关如何在不取消活动后如何执行此操作的反馈和/或建议,并提前致谢!

以下是相关代码,供参考:

def start_game(self):
    self.Bombs += 1
    self.bombsLabel.configure(text = "Total Bombs: %d" % self.Bombs)
    self.b1 = random.randint(1, int(self.canvas.winfo_width()))
    self.b2 = random.randint(1, int(self.canvas.winfo_height()))
    self.b3 = self.b1 + 20
    self.b4 = self.b2 + 20
    self.create_bomb()
    self.parent.after(10000, self.start_game)

和:

# continuously make and explode bombs
def create_bomb(self):
    self.bomb = self.canvas.create_oval(self.b1, 
                                        self.b2, 
                                        self.b3, 
                                        self.b4, 
                                        fill = "red")
    if self.bomb:
        self.parent.after(3000, self.explode_first)


def explode_first(self):
    if self.bomb:
        self.b1 -= 5
        self.b2 -= 5
        self.b3 += 5
        self.b4 += 5
        self.canvas.delete(self.bomb)
        self.bomb = self.canvas.create_oval(self.b1, 
                                        self.b2, 
                                        self.b3, 
                                        self.b4, 
                                        fill = "orange")
        self.parent.after(125, self.explode_second)


def explode_second(self):
    if self.bomb:
        self.b1 -= 5
        self.b2 -= 5
        self.b3 += 5
        self.b4 += 5
        self.canvas.delete(self.bomb)
        self.bomb = self.canvas.create_oval(self.b1, 
                                        self.b2, 
                                        self.b3, 
                                        self.b4, 
                                        fill = "yellow")
        self.parent.after(125, self.explode_third)


def explode_third(self):
    self.b1 -= 5
    self.b2 -= 5
    self.b3 += 5
    self.b4 += 5
    self.canvas.delete(self.bomb)
    self.bomb = self.canvas.create_oval(self.b1,
                                        self.b2,
                                        self.b3,
                                        self.b4, 
                                        fill = "white")
    self.parent.after(125, self.explode_fourth)


def explode_fourth(self):
    self.canvas.delete(self.bomb)

def bomb_disarmed(self):

    print "disarmed the bomb!"
    self.canvas.delete(self.bomb)

2 个答案:

答案 0 :(得分:1)

after方法返回表示已调度事件的ID。如果您保存了ID,则可以致电after_cancel取消活动:

self.after_id = self.parent.after(3000, self.explode_first)
...
self.parent.after_cancel(self.after_id)

答案 1 :(得分:0)

您可以向您正在使用的类添加属性:

self.isDisarmed = False

然后将此行添加到bomb_disarmed

self.isDisarmed = True

然后在explode_first中,添加一个测试以查看炸弹是否已经解除武装:

def explode_first(self):
    if self.bomb:
        if self.isDisarmed:
            self.parent.after(125, self.explode_fourth)   # If bomb is disarmed, skip to the last step, where the bomb is deleted.
        else:                                             # Otherwise, carry on with bomb explosion
            self.b1 -= 5
            self.b2 -= 5
            self.b3 += 5
            self.b4 += 5
            self.canvas.delete(self.bomb)
            self.bomb = self.canvas.create_oval(self.b1, 
                                            self.b2, 
                                            self.b3, 
                                            self.b4, 
                                            fill = "orange")
            self.parent.after(125, self.explode_second)

作为一般原则,我建议将Bomb作为一个类,它有自己的内部属性和方法。这样可以更容易地跟踪炸弹发生的事情,结果应该是什么,并且可以做出多个炸弹等事情。

编辑:

Re:从另一个类的方法绘制App的画布,这是一种方式:

class App:
    def __init__(self, ...):
        self.canvas = Tkinter.Canvas(...)
        self.thingy = SomethingElse()

class SomethingElse:
    def __init__(self, parentApp):
        self.parentApp = parentApp
    def drawSomething(self):
        self.parentApp.canvas.create_oval(...)

a = App(...)
s = SomethingElse(a)
s.drawSomething()