Tkinter: optimize canvas object movement Tkinter: optimize canvas object movement tkinter tkinter

Tkinter: optimize canvas object movement


This is what I feel to be an under-documented Tkinter performance issue. The reason that you see half the oval disappear is that, when detecting what to update on the canvas, it obtains the bbox of whatever needs to be updated, in your case the oval, and then refreshes just that portion of the canvas (for optimization reasons).

However, when you move the oval across the canvas quickly, it leaves the section of the canvas to be updated, meaning that part of the oval will be cutoff, as you see and describe.

This is the Damage/Repair model.

In my opinion, the simplest way to deal with this and fix it is to create a larger, invisible (to the user) object around what you wish to update. This means that Tkinter detects the larger object, and updates the portion of the widget (canvas) around that. The trick is to have the new updated section encompass what you wish to appear, the oval.

You can easily move both the larger invisible object and your oval via a tag system.

To put this in action, you can add the tag of "circle" to your oval, and then create a new oval with the same tag, but coordinates which cover the entire oval. It is also important to specify fill="" and outline="" so that you cannot see the new object.

This looks like:

    self.canvas.create_oval(self.pos[0] - 20, self.pos[1] - 20,                            self.pos[0] + 20, self.pos[1] + 20, fill="blue", tag="circle")    self.canvas.create_oval(self.pos[0] - 40, self.pos[1] - 40, self.pos[0] + 40,                            self.pos[1] + 40, fill="", outline="", tag="circle")

Where the first created oval is your current oval now with a tag, and the second oval is the invisible, larger one.

When you move the oval, instead of moving 1 (which is the ID of your oval at the moment because you create it first), you can move "circle":

    self.canvas.move("circle", *self.speed)

After you implement this, your oval shouldn't show any cut-offs. If you do still see cut-offs, then you can increase the size of the invisible oval, e.g. offsets of 60 instead of 40.