Updated 2018-09-17 16:47:30 by jknapka

To optimize Tk performance, you should consider all the hints for Tcl Performance, as well as these issues.

Tk on Microsoft Windows can be Slow

Tk was developed under X Window. The initial ports to Windows and Macintosh relied upon an X Window emulation. But an architectural mismatch between the two systems resulted in relatively poor performance on Windows. The situation is improving, and many in the Tcl community are considering new Tk implementations that would eliminate this problem. See http://www.multimania.com/fbonnet/Tcl/TkGS/specs.htm --RWT

JH: The above sentiment was general concensus years ago (last century), but the speed of the average PC has washed away most concerns. Tk even runs passably on PocketPC devices now.

[tom] I am dual booting linux & Windows 10. Running filerunner on linux moves from dirctory to sub directory VERY fast, while on Windows 10 it takes forever. I am sure some of this is the file interface (explorer.exe is fast) as well as the window management. (I am using either a wrap version on Windows or the Active State tcl/tk.) What is really going on here?

Tk Canvas

You can speed up drawing of simple lines by explicitly declaring the line to be of zero width. --RWT

The DASH patch was incorporated into 8.3 which allows you to pass a list of coordinates to the various canvas commands rather than individual coordinate parameters. For example:
 set Coords [list 1 2 3 4 5 6 7 8]
 .c create line $Coords

is faster than the previously required
 set Coords [list 1 2 3 4 5 6 7 8]
 eval .c create line $Coords


TJE -- One thing that bothers me is all the memory copying going on, especially for huge coordinate sets. The 'line' object takes a list of coordinates as input and copies them to an internal array of doubles. If I'm generating coordinates externally, I must 1) obtain the data, 2) copy it into a Tcl list, and 3) create/update a line object with that list, leaving a trail of malloc/free waste behind me. What if the line object could recognize and accept a Tcl binary object holding the array of doubles? Well, it works nicely so far! I copied the line object's source file and created my own line type using a single binary object as input. The Tcl_Obj pointer input is type-verified, length-verified (must be even), tagged with Tcl_IncrRef, and stored as the coordinate set. Now I can create 'bline' objects out of huge chunks of binary data I receive from an external source.

Batching GUI Updates

It is far faster to collect all updates you wish to make to a GUI into one place (well, one batch execute between event-servicings) than it is to do it all piece-meal, and it is best to handle updates and protocol management accordingly. You might think that this reduces the responsiveness of the GUI (and in some situations you'd be right) but since display updates are always postponed until an idle event, and since the amount of effort to actually redraw the display is usually significant, it tends to pay to try to do as much at once as you can. Which means more time can actually be spent waiting for user input. Which means the application is more responsive. DKF

Tk Event Procedures

Whenever you bind a script to an event, Tk will either execute the script directly, or, if the script contains '%' substitutions (see the bind man page) it will write a new script and evaluate it.

If you've read Tcl Performance, then you already know that eval is relatively slow, and executing byte-compiled procs is fast. So for speed (and generally good style) use procedures for events. Put the absolute minimum of code in the bind script. For example, binding a listbox mouse click to an action requires you to calculate the listbox selection index because the selection doesn't actually change until *after* the binding fires. (This is described in the Tk Usage FAQ, and is superseded by the <<ListboxSelect>> virtual event in Tcl 8.1)
set lb [listbox .listbox1]
pack $lb
bind $lb <ButtonRelease-1> {select_it %W [%W nearest %y]}
proc select_it { widget n } {
    puts "Selected [$widget get $n]"


Tk application comes up slower than it should? Run TclPro's procheck, if you haven't. It has performance warnings that will show you places to optimize your code.

If startup is a big deal, look for code that could (should) be put in a proc. Also see if you can delay loading some extensions. You can also do the same thing for building GUI forms. Don't construct the toplevel and widgets until you need them, something like:
proc browsdata { } {
    if {[winfo exists .databrowser]} {
        wm deiconify .databrowser
    } else {
        package require SpecialWidgets
        toplevel .datababrowser

Bob Techentin on news:comp.lang.tcl

See the note on Tcl Performance regarding startup time and package loading.

DKF: It can be a big gain to cache canvas items (by moving them off-screen) instead of deleting them when you're finished since this lets you bound the number of canvas ids allocated.

PYK 2012-12-09: DKF describes some changes affecting performance at Rain Storm

Donald Arseneau: In the same vein, canvas items can be cached simply by covering them up. This is most useful when some object has several visual representations. Rather than inserting and removing images to change the appearance, one should raise the desired image. See, for example, Animations on a Canvas.

David Easton: Perhaps a better answer would be if canvas items had a visible property so that they could be hidden properly and presumably this might make some drawing routines faster as hidden items could be ignored - maybe a candidate for 8.5?

Have you tried:
 $canvas itemconfigure $item -state hidden

David Easton: I didn't know about that one - thanks.

Stefan Hartwig: I have the problem to draw very many rectangles (more than 10.000) and the performance of the program is very bad. The scrolling is very slow. Is it possible to disable the automatic tagging of canvas-items (I think this is the problem). Or is there another way to speed up the program? THX

You might want to post to comp.lang.tcl about your problems -- something in your algorithm is probably slowing you down. On my box I'm able to create 10,000 rectangles of random size and color in about 200ms, and that includes the overhead of calling expr about 65,000 times. Scrolling is a tiny bit jerkey though, but still what I would call acceptable.

Is it possible to combine the fast drawing of canvas create rectangle with the speed of scrolling over a canvas image? Whats the difference between drawing rectangles in a canvas and in an image, that makes the drawing in am image such slow?

I'm having performance issues when drawing many lines on a canvas, but adding them only a few at a time. For example, in batches of 100 to a limit of 30000. After the first few groups of lines are drawn, adding a line seems to take longer and longer.

[Joe Knapka]: 9/17/2018 - I have a program that creates about 5000 small rectangles in a canvas and then changes their color via itemconfigure every 1/10 second in response to state changes. (It is a simulator for an LED message sign, which implements various effects such as flashing and animated text.) The performance is adequate in that there is no noticeable delay in updating the canvas. However, on all OS's (Windows, Linux, OS X), it takes a very large amount of CPU activity to keep the canvas updated. When the canvas window is closed, the simulator requires minimal CPU resources, but when the canvas window is open, it uses approximately 1 full CPU core continuously. As a smoke test, I commented out the itemconfigure calls, and this eliminates the high CPU usage. With no deep knowledge of how canvas works internally, I hazard a guess that keeping track of 5000 canvas items and their states is a factor in this behavior. A similar Java program that uses Java2D to draw on a window surface (not using OpenGL) does not suffer from this problem. The canvas widget is a remarkably flexible tool, but perhaps Tk should also provide some lighter-weight widget that supports direct drawing with less computational overhead.