[Tkinter-discuss] tag_bind causes memory leak; fix!

dblank at brynmawr.edu dblank at brynmawr.edu
Sun Jun 11 16:53:24 CEST 2006


> dblank at brynmawr.edu wrote:
>
>> In order to make it so that we can click on these objects, we have code
>> like:
>>
>> self.simulator.canvas.tag_bind("robot-%s" % self.name, "<B1-Motion>",
>>    func=lambda event,robot=self:self.mouse_event(event, "motion",
>> robot))
>>
>> for each object (a robot). First, is there a better way than doing this
>> after every object creation?
>

Fredrik Lundh said:

> I'd recommend using a canvas-level binding instead, and using
> find_overlapping to find the appropriate object for each mouse event.
> e.g.
>
>       def motion(event):
>           widget = event.widget
>           x = widget.canvasx(event.x)
>           y = widget.canvasy(event.y)
>           d = 5 # overlap, in canvas units
>           items = widget.find_overlapping(x-d, y-d, x+d, y+d)
>           if items:
>               ... process items; topmost is last ...
>
>       canvas.bind("<B1-Motion>", motion)

Excellent! This solved the "momery leak" and is much more efficient (so
that we don't have to rebind these events to new objects 10 times a
second). I have posted my adapted solution below. The only sticking point
was that this method doesn't have state about what you were clicking on.
Actually, now that I say that, I'm not sure why it worked before with
object-level bindings.

> (I'd also recommend using a WCK view instead of the Canvas for this
> purpose, but that won't help you with the bindings issue).

When it comes time to rewrite this, I will carefully look at WCK. For now,
this is just a very important bug fix (was losing about a megabyte of
memory a second).

Thanks again!

-Doug

    def dispatch_event(self, event, type):
        widget = event.widget
        x = widget.canvasx(event.x)
        y = widget.canvasy(event.y)
        d = 5 # overlap, in canvas units
        items = widget.find_overlapping(x-d, y-d, x+d, y+d)
        for item in items:
            tags = self.canvas.gettags(item)
            for tag in tags:
                if "robot-" in tag:
                    robot = self.robotsByName[tag[6:]]
                    if "control" in type:
                        self.lastEventRobot = robot
                    else:
                        self.lastEventRobot = None
                    return robot.mouse_event(event, type, robot)
        if self.lastEventRobot:
            return self.lastEventRobot.mouse_event(event, type,
self.lastEventRobot)
    def addMouseBindings(self):
        self.canvas.bind("<B1-Motion>", func=lambda
event=self:self.dispatch_event(event, "motion"))
        self.canvas.bind("<Button-1>",  func=lambda
event=self:self.dispatch_event(event, "down"))
...

> </F>
>
> _______________________________________________
> Tkinter-discuss mailing list
> Tkinter-discuss at python.org
> http://mail.python.org/mailman/listinfo/tkinter-discuss
>




More information about the Tkinter-discuss mailing list