Issue with [update idletasks] and label texts

103 views
Skip to first unread message

Erik Leunissen

unread,
May 29, 2011, 6:34:47 PM5/29/11
to
I see the following issue regarding [update idletasks], with respect to
widget properties like text and border:


Observed behaviour (demonstrated by the attached script)
========================================================
A label's text and border do not respond to [update idletasks] when a
geometry manager re-maps the label[*].

When calling [update] instead of [update idletasks], the label's text
and border are included in the screen update. This demonstrates that the
code for an immediate screen update is already in place. (It's just in
an unexpected place.)

[*] Only the very first time that [update idletasks] is called, the
label's text and border are also updated.


This behaviour has been observed with Tk8.4 and Tk8.5 under Linux.


Expected behaviour
==================
I'd expect that [update idletasks] affects the text and borders of a
label like any other widget property (e.g. background color).

Requiring that a programmer resorts to [update] for this purpose would
be bad, given the well-known dangers associated with that command. If
the programmer refrains from [update], then he's stuck with an ugly
delay of the screen update, in case some compute-intensive task follows
the call to [update idletasks].


Questions
=========
Do others reproduce the behaviour?

If so:

- Is the response to [update idletasks], and how it differs from the
response to [update], intended behaviour?

- Should I file a bug report?


Erik.
--
leunissen@ nl | Merge the left part of these two lines into one,
e. hccnet. | respecting a character's position in a line.

updateIssue.tcl

Andreas Leitgeb

unread,
May 30, 2011, 1:01:40 PM5/30/11
to
Erik Leunissen <lo...@the.footer.invalid> wrote:
> When calling [update] instead of [update idletasks], the label's text
> and border are included in the screen update. This demonstrates that the
> code for an immediate screen update is already in place. (It's just in
> an unexpected place.)
>
> This behaviour has been observed with Tk8.4 and Tk8.5 under Linux.
>
> Questions
>=========
> Do others reproduce the behaviour?

FWIW, it is reproducible with an 8.6b1.2 from September 2010 on
Linux. Haven't yet made the jump to fossil...

> - Should I file a bug report?

I'd say so.

Koen Danckaert

unread,
May 31, 2011, 6:51:58 AM5/31/11
to
Erik Leunissen wrote:
> - Is the response to [update idletasks], and how it differs from the
> response to [update], intended behaviour?

There's nog guarantee that [update idletasks] completes all display updates. See the manual page:

"Most display updates are performed as idle callbacks, so update idletasks will cause them to run. However, there are some kinds of updates that only happen in response to events, such as those triggered by window size changes; these updates will not occur in update idletasks."

I would recommend to use only one button and configure its -text and -background every time. That's a less "heavy" display update.

--Koen

Erik Leunissen

unread,
May 31, 2011, 9:01:51 AM5/31/11
to
Koen Danckaert wrote:
>
> There's nog guarantee that [update idletasks] completes all display
> updates. See the manual page:
>
> "Most display updates are performed as idle callbacks, so update
> idletasks will cause them to run. However, there are some kinds of
> updates that only happen in response to events, such as those triggered
> by window size changes; these updates will not occur in update idletasks."
>

OK. So it is documented behaviour. Thanks for pointing that out.

Since this documented behaviour causes an interface to behave ugly in
the use case presented, I question whether that behaviour is useful[*].

So, what are the reasons for not including these updates in [update
idletasks]?


Anyone familiar enough with the subject to explain/comment on that?


[*] Especially so since it appears that the desired behaviour has
already been coded for, but currently can only be evoked by the crude
[update].


> I would recommend to use only one button and configure its -text and
> -background every time. That's a less "heavy" display update.


But then we're departing from the *use case* where you *need to unmap* a
widget temporarily. (Otherwise, yes, of course.)


Erik.


>
> --Koen

Erik Leunissen

unread,
May 31, 2011, 12:33:33 PM5/31/11
to

Thanks!

>> - Should I file a bug report?
>
> I'd say so.
>

Well, I'm unsure. The documentation leaves room for justification of
this behaviour (as pointed out by Koen Danckaerts in this thread).

Personally I'm not satisfied by that, since the use case is still valid,
regardless what the documentation says.

I'll wait a bit longer to see if an expert in this subject can provide
information about the reasons for this behaviour.

Joe English

unread,
Jun 1, 2011, 5:11:21 PM6/1/11
to
Erik Leunissen wrote:
> Koen Danckaert wrote:
>> There's no guarantee that [update idletasks] completes all display

>> updates. See the manual page:
>>
>> "Most display updates are performed as idle callbacks, so update
>> idletasks will cause them to run. However, there are some kinds of
>> updates that only happen in response to events, such as those triggered
>> by window size changes; these updates will not occur in update idletasks."
>
> OK. So it is documented behaviour. Thanks for pointing that out.
>
> Since this documented behaviour causes an interface to behave ugly in
> the use case presented, I question whether that behaviour is useful[*].
>
> So, what are the reasons for not including these updates in [update
> idletasks]?


As noted, most Tk widgets redraw themselves at idle-time,
so [update idletasks] will perform any pending redisplays.

They generally *schedule* redisplays in response to <Expose>
and <Configure> events, and these come in through the main
event loop. So if you [update idletasks] immediately after
[pack]ing a window, it won't necessarily redraw itself
because it might not know that it needs to be redrawn yet!

You can see this in action if you add the following to
the original test script:

bind all <Map> { puts "MAP: %W" }
bind all <Expose> { puts "EXPOSE: %W" }

You can force a redisplay without reentering the main event loop
by sending a synthetic <Expose> event:

pack $w ...
event generate $w <Expose> -when now
update idletasks

('-when now' is the default for [event generate],
so strictly speaking it's unnecessary, but I like
to write it out explicitly in cases where it makes
a difference, as it does here.)


--Joe English

Erik Leunissen

unread,
Jun 2, 2011, 6:00:44 PM6/2/11
to
Joe English wrote:
>
> As noted, most Tk widgets redraw themselves at idle-time,
> so [update idletasks] will perform any pending redisplays.
>
> They generally *schedule* redisplays in response to <Expose>
> and <Configure> events, and these come in through the main
> event loop. So if you [update idletasks] immediately after
> [pack]ing a window, it won't necessarily redraw itself
> because it might not know that it needs to be redrawn yet!
>
> You can see this in action if you add the following to
> the original test script:
>
> bind all <Map> { puts "MAP: %W" }
> bind all <Expose> { puts "EXPOSE: %W" }
>
> You can force a redisplay without reentering the main event loop
> by sending a synthetic <Expose> event:
>
> pack $w ...
> event generate $w <Expose> -when now
> update idletasks
>
> ('-when now' is the default for [event generate],
> so strictly speaking it's unnecessary, but I like
> to write it out explicitly in cases where it makes
> a difference, as it does here.)
>

This is great information! Thanks a lot.

It solves a few long-standing issues that I have been working around
using ugly hacks related to the event loop.

You made my day.


Now, there is something that I still don't understand:

What you explain about scheduling redisplays, seems to hold for an
entire widget. Then why is it that, in response to [update idletasks], I
do see the background colour of the remapped widget, but not its text?

Erik.


>
> --Joe English

Joe English

unread,
Jun 2, 2011, 7:25:48 PM6/2/11
to
Erik Leunissen wrote:
>
> Now, there is something that I still don't understand:
>
> What you explain about scheduling redisplays, seems to hold for an
> entire widget. Then why is it that, in response to [update idletasks], I
> do see the background colour of the remapped widget, but not its text?

Many core Tk widgets set the background_pixel X window attribute
to match their '-background' option. What you're seeing is
drawn by the X server in response to the widget being mapped,
not by Tk.

You won't see this effect on Windows or OSX (since
XSetWindowBackground() is a stub on those platforms)
or with ttk::* widgets (since they don't bother
setting the window background).

The reason it happens at idle-time and not immediately after
[pack] is that [pack] and [grid] also defer mapping slave
windows to idle-time.


--Joe English

APN

unread,
Jun 3, 2011, 12:58:14 AM6/3/11
to
On Jun 3, 3:00 am, Erik Leunissen <l...@the.footer.invalid> wrote:
>
> This is great information! Thanks a lot.
>
> It solves a few long-standing issues that I have been working around
> using ugly hacks related to the event loop.
>

Seconded! I've never seen this technique mentioned - not in any of the
Tcl books I've read, nor the wiki or the newsgroup.

/Ashok

APN

unread,
Jun 3, 2011, 1:37:00 AM6/3/11
to
Wikified in http://wiki.tcl.tk/13859 as I have not seen this hint/
technique anywhere else

On Jun 2, 2:11 am, Joe English <jengl...@fdip.bad-monkeys.org> wrote:

> As noted, most Tk widgets redraw themselves at idle-time,
> so [update idletasks] will perform any pending redisplays.
>
> They generally *schedule* redisplays in response to <Expose>
> and <Configure> events, and these come in through the main
> event loop.  So if you [update idletasks] immediately after
> [pack]ing a window, it won't necessarily redraw itself
> because it might not know that it needs to be redrawn yet!
>
> You can see this in action if you add the following to
> the original test script:
>
>     bind all <Map> { puts "MAP: %W" }
>     bind all <Expose> { puts "EXPOSE: %W" }
>
> You can force a redisplay without reentering the main event loop
> by sending a synthetic <Expose> event:
>
>     pack $w ...
>     event generate $w <Expose> -when now
>     update idletasks
>

> --Joe English

Erik Leunissen

unread,
Jun 3, 2011, 6:06:01 PM6/3/11
to
Joe English wrote:
>
> Many core Tk widgets set the background_pixel X window attribute
> to match their '-background' option. What you're seeing is
> drawn by the X server in response to the widget being mapped,
> not by Tk.
> ...

Thanks,

Erik.

Erik Leunissen

unread,
Jun 4, 2011, 7:16:10 PM6/4/11
to
On Jun 1, 11:11 pm, Joe English <jengl...@fdip.bad-monkeys.org> wrote:
>
> You can force a redisplay without reentering the main event loop
> by sending a synthetic <Expose> event:
>
>     pack $w ...
>     event generate $w <Expose> -when now
>     update idletasks
>
> ('-when now' is the default for [event generate],
> so strictly speaking it's unnecessary, but I like
> to write it out explicitly in cases where it makes
> a difference, as it does here.)
>

Exploring the [event] manpage, I come across the phrase:


<quote>
If the -when option is not specified, the event is processed
immediately: all of the handlers for the event will complete
before the event generate command returns.
<unquote>


From this I understand that an [update idletasks] is superfluous after
doing [event generate $w <Expose> -when now].

Is my understanding correct?

(When testing this with my test script by *replacing* [update
idletasks] with [event generate ...], I do indeed get the intended
immediate display redraw. But that may be shear luck.)


Erik.

Joe English

unread,
Jun 5, 2011, 2:51:59 PM6/5/11
to
Erik Leunissen wrote:

> Joe English wrote:
>> You can force a redisplay without reentering the main event loop
>> by sending a synthetic <Expose> event:
>> [...]

>>
> Exploring the [event] manpage, I come across the phrase:
>
><quote>
> If the -when option is not specified, the event is processed
> immediately: all of the handlers for the event will complete
> before the event generate command returns.
><unquote>
>
> From this I understand that an [update idletasks] is superfluous after
> doing [event generate $w <Expose> -when now].
>
> Is my understanding correct?

No; [update idletasks] is still necessary.

Widget <Expose> handlers typically do not redraw
immediately; they only schedule a redraw on the idle
queue (if one is not already pending).

[event generate $w <Expose> -when now] executes
all of $w's <Expose> handlers immediately, without
touching the event queue or the idle queue.

So you should not expect to see the widget refreshed
until Tcl gets around to processing the idle queue.


> (When testing this with my test script by *replacing* [update
> idletasks] with [event generate ...], I do indeed get the intended
> immediate display redraw. But that may be shear luck.)

Double-check that -- I don't see that behavior.

Omitting [update idletasks], the old widget is
not unmapped, the new widget is not mapped,
and the "Swap Labels" button stays pressed
until the [after 2000] completes. That's
what I'm seeing anyway.


--Joe

Erik Leunissen

unread,
Jun 5, 2011, 3:19:14 PM6/5/11
to
Joe English wrote:

>
>> (When testing this with my test script by *replacing* [update
>> idletasks] with [event generate ...], I do indeed get the intended
>> immediate display redraw. But that may be shear luck.)
>
> Double-check that -- I don't see that behavior.
>
> Omitting [update idletasks], the old widget is
> not unmapped, the new widget is not mapped,
> and the "Swap Labels" button stays pressed
> until the [after 2000] completes. That's
> what I'm seeing anyway.
>

You're right. It appears that I am seeing an immediate redraw because I
sourced the script from inside tkcon.

When using a bare tclsh, I see what you see.

Thanks,

Erik.


>
> --Joe

Reply all
Reply to author
Forward
0 new messages