【问题标题】:canvas.itemconfig results in infinite event-loopcanvas.itemconfig 导致无限事件循环
【发布时间】:2017-12-24 11:01:18
【问题描述】:

我尝试在每个单元格上绘制一个带有标记的 3x3 小板。 此标记应仅在用鼠标触摸单元格时显示。 这工作一次,两次,有时 3 次,但随后事件循环无限“触发”(总是相同的事件)......

import tkinter as tk

cellsize = 50

class Board(tk.Canvas):

    def __init__(self):

        tk.Canvas.__init__(self)

        for row in range(3):
            for column in range(3):
                ulx, uly = column*cellsize, row*cellsize
                lrx, lry = ulx+cellsize, uly+cellsize
                _cell = self.create_rectangle(ulx, uly, lrx, lry,
                                              fill='green')
                _right = self.create_rectangle(ulx+39, uly+20, lrx-1, lry-20,
                                              fill='red',
                                              state='hidden')
                self.tag_bind(_cell, '<Enter>', 
                              lambda e, r=_right: self.show_pos('on', r))
                self.tag_bind(_cell, '<Leave>', 
                              lambda e, r=_right: self.show_pos('off', r))

    def show_pos(self, onoff, right):

        print('{} {}'.format(onoff, right))
        if onoff == 'on':
            self.itemconfig(right, state='normal')
        elif onoff == 'off':
            self.itemconfig(right, state='hidden')

root = tk.Tk()
Board().grid()
root.mainloop()

也许这是坚持 self.itemconfigure 语句,因为做其他事情(例如更新状态行)按预期工作。

有解决办法吗?

提前谢谢

马文

补充:
更准确地说:它似乎坚持使用 'state=..."
将“show_pos”中的 itemconfig 更改为“fill=...”按预期工作。 所以标题应该是
'canvas.itemconfig(state='...' 导致无限事件循环'

【问题讨论】:

  • 因为在状态更改(Tkinter.py,def _cnfmerge)之后调用“更新”,您的状态更改会导致额外的状态更改 - 足够快地运行鼠标会导致您的循环。尝试通过鼠标位置计算而不是进入/离开来实现绑定,你应该很好。

标签: python tkinter python-3.5 tkinter-canvas


【解决方案1】:

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

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

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

        self.bind('&ltMotion&gt', 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)

这不会触发您在方法中绑定的休假事件,因此应该可以解决您的问题。

如果您出于某种原因不想采用这种方法,您只能绑定到 enter 并使用 find_withtag("indicator")-Approach 隐藏所有其他指标

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

【讨论】:

  • 谢谢你的回答。
  • 根据您之前的简短评论,我使用了 find_closest。我将单元格和指标存储在一个字典中,并以相应的 bbox 值作为键。 “标签”的东西并没有出现在我的脑海中。简而言之:我不是很成功。但是您的解决方案——尽管如此优雅得多——也不起作用。有时推动鼠标后,它会无限卡在while..-loop中。我决定使用更简单的解决方案,并以背景颜色绘制指示器,并在鼠标“进入”指示器时进行处理。
猜你喜欢
  • 2012-04-28
  • 2017-06-10
  • 2020-08-27
  • 2021-05-07
  • 2012-08-24
  • 2020-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多