Python canvas.itemconfig导致无限事件循环

Python canvas.itemconfig导致无限事件循环,python,tkinter,python-3.5,tkinter-canvas,Python,Tkinter,Python 3.5,Tkinter Canvas,我试着在每个单元格上画一块3x3的小黑板,上面有一个标记。 仅当鼠标触摸单元格时,此标记才会显示。 这可以工作一次,两次,有时三次-但是随后事件循环无限地“激发”(总是相同的事件) 将tkinter作为tk导入 单元大小=50 课程板(tk.Canvas): 定义初始化(自): tk.Canvas.\uuuuu init\uuuuuuuu(自) 对于范围(3)中的行: 对于范围(3)中的列: ulx,uly=列*单元大小,行*单元大小 lrx,lry=ulx+cellsize,uly+cells

我试着在每个单元格上画一块3x3的小黑板,上面有一个标记。 仅当鼠标触摸单元格时,此标记才会显示。 这可以工作一次,两次,有时三次-但是随后事件循环无限地“激发”(总是相同的事件)

将tkinter作为tk导入
单元大小=50
课程板(tk.Canvas):
定义初始化(自):
tk.Canvas.\uuuuu init\uuuuuuuu(自)
对于范围(3)中的行:
对于范围(3)中的列:
ulx,uly=列*单元大小,行*单元大小
lrx,lry=ulx+cellsize,uly+cellsize
_单元格=自身。创建矩形(ulx、uly、lrx、lry、,
填充(绿色)
_右=自身。创建矩形(ulx+39、uly+20、lrx-1、lry-20、,
填写“红色”,
状态(隐藏)
self.tag_bind(_单元格,
lambda e,r=_right:self.show_pos('on',r))
self.tag_bind(_单元格,
lambda e,r=_right:self.show_pos('off',r))
def显示位置(自身、接通断开、右侧):
打印({}{}.format(onoff,右))
如果onoff==“on”:
self.itemconfig(右,state='normal')
elif onoff==“off”:
self.itemconfig(右,state='hidden')
root=tk.tk()
Board().grid()
root.mainloop()
这可能是因为执行其他操作(例如更新状态行)可以按预期工作,所以会被粘贴到self.itemconfigure语句中

有解决办法吗

提前Thx

马文

添加:
更准确地说:它似乎坚持使用“state=…”
在“show_pos”中将itemconfig更改为“fill=…”,效果与预期一样。 所以标题应该是

“canvas.itemconfig(state=”…“导致无限事件循环”

使用鼠标位置方法,您可以使用:

class BoardX(tk.Canvas):
    __cells=None
    __indicators=None
    def __init__(self):
        tk.Canvas.__init__(self)

        self.__cells=[]
        self.__indicators=[]

        self.bind('<Motion>', self.show_pos)

        for row in range(3):
            for column in range(3):
                ulx, uly = column*cellsize, row*cellsize
                lrx, lry = ulx+cellsize, uly+cellsize
                self.__cells.append(self.create_rectangle(ulx, uly, lrx, lry,
                                              fill='green', tags="cell"))
                self.__indicators.append(self.create_rectangle(ulx+39, uly+20, lrx-1, lry-20,
                                              fill='red',
                                              state='hidden', tags="indicator"))
    def show_pos(self, event):
        """ Get closest widget or widget that we are above,
            tagged "cell" and indicate it
        """

        # the loop is needed for not to run into value errors
        halo=0
        widget = self.find_closest(event.x, event.y, halo=halo)

        # edit - avoid loop!
        if not widget[0] in self.find_withtag("cell"):
            return

        index = self.__cells.index(widget[0])

        for i in range(len(self.__indicators)):
            state='hidden'
            if i == index:
                state='normal'
            self.itemconfig(self.__indicators[i], state=state)

这不会使您的方法中的事件受到约束,因此应该解决您的问题

如果您出于任何原因不想采用这种方法,您只能绑定到
输入
并使用
查找带标记的指示器(“指示器”)
-方法隐藏其他每个指示器

编辑
已更正代码示例以避免循环。

使用鼠标位置方法,您可以使用:

class BoardX(tk.Canvas):
    __cells=None
    __indicators=None
    def __init__(self):
        tk.Canvas.__init__(self)

        self.__cells=[]
        self.__indicators=[]

        self.bind('<Motion>', self.show_pos)

        for row in range(3):
            for column in range(3):
                ulx, uly = column*cellsize, row*cellsize
                lrx, lry = ulx+cellsize, uly+cellsize
                self.__cells.append(self.create_rectangle(ulx, uly, lrx, lry,
                                              fill='green', tags="cell"))
                self.__indicators.append(self.create_rectangle(ulx+39, uly+20, lrx-1, lry-20,
                                              fill='red',
                                              state='hidden', tags="indicator"))
    def show_pos(self, event):
        """ Get closest widget or widget that we are above,
            tagged "cell" and indicate it
        """

        # the loop is needed for not to run into value errors
        halo=0
        widget = self.find_closest(event.x, event.y, halo=halo)

        # edit - avoid loop!
        if not widget[0] in self.find_withtag("cell"):
            return

        index = self.__cells.index(widget[0])

        for i in range(len(self.__indicators)):
            state='hidden'
            if i == index:
                state='normal'
            self.itemconfig(self.__indicators[i], state=state)

这不会使您的方法中的事件受到约束,因此应该解决您的问题

如果您出于任何原因不想采用这种方法,您只能绑定到
输入
并使用
查找带标记的指示器(“指示器”)
-方法隐藏其他每个指示器

编辑
代码示例已更正,以避免循环。

由于在状态更改(Tkinter.py,def\u cnfmerge)后调用了“update”,您的状态更改会导致额外的状态更改,这会使您的循环中出现足够快的鼠标。尝试通过鼠标位置计算来实现绑定,而不是使用enter/leave,您应该很好。as“状态更改后将调用“更新”(Tkinter.py,def_cnfmerge)您的状态更改会导致其他状态更改,这会导致循环中足够快地运行鼠标。尝试通过鼠标位置计算而不是进入/离开来实现绑定,您应该很好。谢谢您的回答。根据您之前的简短评论,我使用find_closest进行了处理。我存储了单元格和指示器在一个以相应的bbox值作为键的dict中。“标记”的东西没有出现在我的脑海中。简而言之:我不是很成功。但是你的解决方案——尽管更加优雅——也不起作用。有时在按住鼠标后,它会在while…-循环中无限受阻。我决定使用一个更简单的解决方案并绘制指示器如果鼠标“进入”指示器,则使用背景色和手柄。谢谢您的回答。根据您之前的简短评论,我使用find_Nestest进行了处理。我将单元格和指示器存储在dict中,并将相应的bbox值作为键。我没有想到“标记”的内容。简而言之,我不是很成功。但您的解决方案-非太不雅致了-也不起作用。有时在推鼠标后,它会在while…-循环中无限地阻塞。我决定使用一种更简单的解决方案,在鼠标“进入”指示器时,用背景色和手柄绘制指示器。