Notes on Tkinter Performance
Updated July 14, 2002 | Posted April 20, 1999 | Fredrik Lundh
From a comp.lang.python post
Note that the canvas seems to have respectable optimizations in place so the less that is visible (e.g. the more you’re zoomed in, the faster redraws get. Also if only a partial area needs redrawn, it redraws it fairly quickly relative to the full-expose frame rate. It’s obvious there’s some optimization going on when you load to make drawing faster.
Some background: the Canvas widget uses a straight-forward damage/repair model. Changes to the canvas, and external events such as Expose, all update a single “dirty rectangle”. They also register an idle task (after_idle) which redraws the canvas when you get back to the main loop.
When it’s time to redraw the canvas, the widget starts by allocating a pixmap (on X windows, this is an image memory stored on the display) with the same size as the dirty rectangle.
It then loops over the canvas items, and redraws all items whose bounding box touch the dirty rectangle (this means that diagonal lines may be redrawn also if they don’t actually cover the rectangle, but this is usually no big deal).
Finally, the widget copies the pixmap to the display, and releases the pixmap. The copy operation is a very fast operation on most modern hardware.
A few additional notes:
Most Tk widgets use double-buffering to prevent flicker (this includes simple widgets like buttons and labels). There’s no way to change this in current version of Tk.
Most Tk widgets also use delayed drawing. That is, they respond to modifications and external events by scheduling an idle task, not by updating the screen directly. In some cases, this can result in an application that feels a bit sluggish. There’s no way to change this in current versions of Tk, but you can work around this problem by calling update_idletasks whenever you’ve changed anything (also see below).
The repeated allocation of pixmaps can seriously affect performance if you’re animating stuff in a maximized window on a large truecolor display… (we all have 1800x1440 32-bit displays, don’t we?)
Since the canvas uses a single dirty rectangle, you can get better performance in some situations by forcing updates. For example, if you’re changing things in different parts of the canvas without returning to the main loop, adding explicit calls to update_idletasks() allows the canvas to update a few small rectangles, instead of a large one with many more objects.
- The Text widget is a bit smarter than the canvas: it keeps track of what’s already drawn, and can move things around on the screen instead of redrawing everything all the time.
Guess I should mention uiToolkit here, but I’ll leave that for another day… (but briefly, uiToolkit allows you to switch off double-buffering or keep the buffer between updates, supports immediate redraw, and allows you to implement widgets with more sophisticated damage control).