Python 特金特:为什么矩形在与移动的蓝色矩形接触时仍保持黄色?

Python 特金特:为什么矩形在与移动的蓝色矩形接触时仍保持黄色?,python,tkinter,Python,Tkinter,这是“Tkinter GUI应用程序开发食谱-2018”中名为“检测项目之间的冲突”的食谱。 这段代码可以完美地运行:您可以通过按方向键移动较大的矩形,而四个较小的矩形在拐角处保持静止。一旦较大的触摸到较小的任何一个,后者将从绿色变为黄色。然而,由于在“进动”循环中有两个顺序的“for”循环,我认为被触摸的较小矩形应该经常改变颜色,这与运行时的观察结果不符。为了验证我的分析是正确的,我在第一个循环中放置了“print”(“item:+str(item))”来监控情况,结果是在第一个“for”循环

这是“Tkinter GUI应用程序开发食谱-2018”中名为“检测项目之间的冲突”的食谱。 这段代码可以完美地运行:您可以通过按方向键移动较大的矩形,而四个较小的矩形在拐角处保持静止。一旦较大的触摸到较小的任何一个,后者将从绿色变为黄色。然而,由于在“进动”循环中有两个顺序的“for”循环,我认为被触摸的较小矩形应该经常改变颜色,这与运行时的观察结果不符。为了验证我的分析是正确的,我在第一个循环中放置了“print”(“item:+str(item))”来监控情况,结果是在第一个“for”循环中,当其中一个与较大的移动矩形碰撞时,所有四个较小的矩形都变回绿色。这显然很奇怪。有谁能解释一下这种现象吗?谢谢 代码如下:

import tkinter as tk


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Detecting collisions between items")

        self.canvas = tk.Canvas(self, bg="white")
        self.canvas.pack()
        self.update()
        self.width = w = self.canvas.winfo_width()
        self.height = h = self.canvas.winfo_height()

        pos = (w / 2 - 15, h / 2 - 15, w / 2 + 15, h / 2 + 15)
        self.item = self.canvas.create_rectangle(*pos, fill="blue")
        positions = [(60, 60), (w - 60, 60), (60, h - 60), (w - 60, h - 60)]
        for x, y in positions:
            self.canvas.create_rectangle(x - 10, y - 10, x + 10, y + 10,
                                         fill="green")

        self.pressed_keys = {}
        self.bind("<KeyPress>", self.key_press)
        self.bind("<KeyRelease>", self.key_release)
        self.process_movements()

    def key_press(self, event):
        self.pressed_keys[event.keysym] = True

    def key_release(self, event):
        self.pressed_keys.pop(event.keysym, None)

    def process_movements(self):
        all_items = self.canvas.find_all()
        for item in filter(lambda i: i is not self.item, all_items):
            self.canvas.itemconfig(item, fill="green")
            print("item:" + str(item))  # monitoring items which have been turned green
        x0, y0, x1, y1 = self.canvas.coords(self.item)
        items = self.canvas.find_overlapping(x0, y0, x1, y1)
        for item in filter(lambda i: i is not self.item, items):
            self.canvas.itemconfig(item, fill="yellow")
        off_x, off_y = 0, 0
        speed = 3
        if 'Right' in self.pressed_keys:
            off_x += speed
        if 'Left' in self.pressed_keys:
            off_x -= speed
        if 'Down' in self.pressed_keys:
            off_y += speed
        if 'Up' in self.pressed_keys:
            off_y -= speed

        pos_x = x0 + (x1 - x0) / 2 + off_x
        pos_y = y0 + (y1 - y0) / 2 + off_y
        if 0 <= pos_x <= self.width and 0 <= pos_y <= self.height:
            self.canvas.move(self.item, off_x, off_y)

        self.after(100, self.process_movements)


if __name__ == "__main__":
    app = App()
    app.mainloop()

将tkinter作为tk导入
类应用程序(tk.tk):
定义初始化(自):
super()。\uuuu init\uuuuu()
self.title(“检测项目之间的冲突”)
self.canvas=tk.canvas(self,bg=“白色”)
self.canvas.pack()
self.update()
self.width=w=self.canvas.winfo_width()
self.height=h=self.canvas.winfo_height()
位置=(w/2-15,h/2-15,w/2+15,h/2+15)
self.item=self.canvas.create_矩形(*pos,fill=“blue”)
职位=[(60,60),(w-60,60),(60,h-60),(w-60,h-60)]
对于x,y的位置:
创建一个矩形(x-10,y-10,x+10,y+10,
fill=“绿色”)
自按_键={}
self.bind(“,self.key_按)
self.bind(“,self.key\u release)
self.process_movements()
按def键(自身,事件):
自按按键[event.keysym]=真
def钥匙释放(自身、事件):
self.pressed_keys.pop(event.keysym,无)
def过程_移动(自):
all\u items=self.canvas.find\u all()
对于筛选器中的项(lambda i:i不是self.item,所有_项):
self.canvas.itemconfig(item,fill=“绿色”)
打印(“项目:+str(项目))#已变为绿色的监控项目
x0,y0,x1,y1=self.canvas.coords(self.item)
items=self.canvas.find_重叠(x0,y0,x1,y1)
对于筛选器中的项(lambda i:i不是self.item,items):
self.canvas.itemconfig(item,fill=“yellow”)
off_x,off_y=0,0
速度=3
如果按下自选按钮中的“右键”:
off_x+=速度
如果按下自选按钮中的“左”:
off_x-=速度
如果按下自选按钮中的“向下”:
关闭y+=速度
如果按下自选按钮中的“向上”:
off_y-=速度
位置x=x0+(x1-x0)/2+关闭
位置y=y0+(y1-y0)/2+关闭y

如果0如果您希望对重叠项具有闪烁效果,即绿-黄-绿-黄等,则只需第二个for循环即可找到重叠项。如果发现重叠项,请将其填充颜色改为黄色,并使用
.after()
将其填充颜色改回绿色来安排任务:

def process_movements(self):
    x0, y0, x1, y1 = self.canvas.coords(self.item)
    items = self.canvas.find_overlapping(x0, y0, x1, y1)
    for item in items:
        if item is not self.item:
            self.canvas.itemconfig(item, fill="yellow")
            # schedule a task 50ms later to reset fill color to green
            self.after(50, lambda i=item: self.canvas.itemconfig(i, fill="green"))

    off_x, off_y = 0, 0
    speed = 3
    if 'Right' in self.pressed_keys:
        off_x += speed
    if 'Left' in self.pressed_keys:
        off_x -= speed
    if 'Down' in self.pressed_keys:
        off_y += speed
    if 'Up' in self.pressed_keys:
        off_y -= speed

    pos_x = x0 + (x1 - x0) / 2 + off_x
    pos_y = y0 + (y1 - y0) / 2 + off_y
    if 0 <= pos_x <= self.width and 0 <= pos_y <= self.height:
        self.canvas.move(self.item, off_x, off_y)

    self.after(100, self.process_movements)
def过程_移动(自身):
x0,y0,x1,y1=self.canvas.coords(self.item)
items=self.canvas.find_重叠(x0,y0,x1,y1)
对于项目中的项目:
如果项目不是self.item:
self.canvas.itemconfig(item,fill=“yellow”)
#计划50毫秒后的任务,将填充颜色重置为绿色
self.after(50,lambda i=item:self.canvas.itemconfig(i,fill=“green”))
off_x,off_y=0,0
速度=3
如果按下自选按钮中的“右键”:
off_x+=速度
如果按下自选按钮中的“左”:
off_x-=速度
如果按下自选按钮中的“向下”:
关闭y+=速度
如果按下自选按钮中的“向上”:
off_y-=速度
位置x=x0+(x1-x0)/2+关闭
位置y=y0+(y1-y0)/2+关闭y

如果第一个for循环中为0,则已将项目的填充颜色设置为绿色。所以你说的奇怪其实是正常的结果。@acw1668我想你误解了我说的话。较大矩形击中的较小矩形的颜色应为绿色(第一个为循环)-黄色(第二个为循环)-绿色(第一个为循环)-黄色(第二个为循环)-绿色(第一个为循环)-黄色(第二个为循环),依此类推,如果后者始终与前者重叠。然而,这与观察到的运行结果不一致。为什么?虽然您在第一个for循环中将所有项都更改为绿色,但在第二个for循环中将重叠项更改为黄色。所以您只能看到黄色的重叠项。