I am developing a GUI application that has a button that, upon being
clicked, invokes a function that dumps messages to a listbox.
I noticed that, after clicking the button, there is a long pause,
where it appears that nothing is happening. Then all of a sudden,
everything that apparently was actually dumped to the listbox while it
seemed that nothing was happening, suddenly appears. It turns out that
the duration of the pause is, not surprisingly, equivalent to the
duration it legitimately takes to do the things in my command
function.
I suspect that Tk is invoking the command that is associated with the
down-click activation of the button while not honoring the Microsost
Windows SendMessage() calls that happen inside the command [the
equivalent actually], but so many people would have experienced the
same problem, so I must be doing something wrong.
What am I doing wrong?
TIA,
-Le Chaud Lapin-
You are not giving Tcl/Tk a chance to process the display events to redraw
the screen. Read the man page for "update", pay particular attention to the
"idletask" option/subcommand section.
If the above is not enough of a hint, buy a 2x4 and repetitively hit
yourself between the eyes until understanding is achived.
--
+------------------------------------------------------------------------+
| Gerald W. Lester, President, KNG Consulting LLC |
| Email: Gerald...@kng-consulting.net |
+------------------------------------------------------------------------+
I was under the impression that if I invoke a call to the Tk GUI
subsystem to say, add a line to a listbox, then the line will be added
at the moment that the call to Tk is made. In other words, my GUI
should update before the call to listbox insert returns. Is this not
the case?
This is the way the underlying OS (Windows) works. A call to the
display part of the GUI subsystem, in general, manifests on the screen
before the return is made from the call, unless the call is inherently
asynchronous.
Note that I am not concerned with the fact that the GUI does not
respond to mouse-clicks/keyboard/etc. type user-input while my
computation is in execution. What concerns me is that my computation
tells the screen to draw a line while it is computing, and the line is
not rendered until after the entire computation is complete.
This tells me that the underlying GUI rendering model for Tk is
inherently asynchronous. If screen output were synchronous, I would
see visible changes on scrren before call from computation is
finished.
-Le Chaud Lapin-
Wrong impression, never has been that way on any supported OS.
> ...
>
> This tells me that the underlying GUI rendering model for Tk is
> inherently asynchronous. If screen output were synchronous, I would
> see visible changes on scrren before call from computation is
> finished.
The "redraw" events from the window manager need to be processed before the
changes you make are visible.
> On 8/19/11 12:45 PM, Le Chaud Lapin wrote:
>>
>> I was under the impression that if I invoke a call to the Tk GUI
>> subsystem to say, add a line to a listbox, then the line will be added
>> at the moment that the call to Tk is made. In other words, my GUI
>> should update before the call to listbox insert returns. Is this not
>> the case?
>
> Wrong impression, never has been that way on any supported OS.
Although at least [text] widget can give a false sign of this kind of
trickery by delaying its internal updates. It always makes me blink twice
when button comes up first and contents changes later.
--
-Kaitzschu
set s TCL\ ;wh 1 {pu [set s [st ra $s 1 3][st in $s 0]]\033\[1A;af 99}
"Good thing programmers don't build bridges
[the same way as Kaitzschu writes code]."
--John Kelly in comp.lang.tcl
You can also be lead to think that way if you "try" things out in Tk's
console or if you use Tkcon since they are in the event loop when "waiting"
for input from the keyboard.
Well, it's logically there. It just hasn't been drawn yet, which is
actually a good thing: you might add a line, remove another, tweak what
is highlighted and change the highlight style in response to a single
event and you wouldn't want the display to flicker after each of those
changes. Postponing the redraw allows the changes to be grouped together
into a single display update, which looks enormously more professional.
What actually happens is that the redisplay is postponed until the code
has Nothing Better To Do. Formally, that means that it is postponed
until the application is about to wait for events to come, that is, at
the point when it is no longer handling an event and the queue of events
is clear. You can make this happen sooner if necessary by doing [update
idletasks] (or [update]) but that's usually not a great idea unless
you're doing a long bit of processing. (That command services the queue
of things to do "when idle".)
It's an exceptionally clever system, as it means that Tk's GUI seems
responsive (even on slow systems, though admittedly the double buffering
that is used heavily internally also helps there) and without incomplete
display updates. However, in the (minority) case where you're doing long
processing in a button's command callback it has its down-sides. Putting
[update idletasks] in suitable places will help a lot, though
redesigning your workload so that it happens asynchronously would be
better. (The details of that depend on what you're doing, which is not
something you've described in great depth.)
Donal.