Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

update vs. update idletasks or other ways to force pack to redraw widgets

672 views
Skip to first unread message

rianmonnahan

unread,
Feb 20, 2015, 10:50:24 AM2/20/15
to
Hi all,

I'm running Active Tcl/tk patchlevel 8.6.3 on a MacOS 10.10.

I'm working through some of the examples in Practical Programing in Tcl and Tk.

Specifically, I'm working on example 12-6.

wm geometry . 200x100

. config -bg black

#Create two frames to hold and open cavity

frame .prop -bg white -height 80 -width 20
frame .base -bg grey50 -height 20 -width 20

pack .prop
pack .base -side bottom -fill x

#Float a labe and the prop in the cavity

label .foo -text Foo

pack .prop -side right -expand true -anchor sw
pack .foo -side right -expand true -anchor ne

foreach anchor {center n ne e se s sw w nw center } {

puts $anchor

pack .foo .prop -anchor $anchor

#***** THIS IS THE PB *****#
update
#update idletasks DOES NOT WORK

after 500

}

Welch suggests using "update idletask" for force the geometry manager to redraw the screen after each interration of pack. This to show the effects of different anchor values.

Well, it does not work. If you run the code with "update idle," you will set the variables change in the terminal window but the main (graphical) window will not be updated until the program exits the foreach loop.

If you use update (a no-no, I'm hear), the graphical window is redrawn after each iteration of the loop.

Any ideas on better ways to force a refresh in this context?

Many thanks.






Rich

unread,
Feb 20, 2015, 1:47:31 PM2/20/15
to
rianmonnahan <rian.m...@gmail.com> wrote:
> Hi all,

> I'm running Active Tcl/tk patchlevel 8.6.3 on a MacOS 10.10.

> I'm working through some of the examples in Practical Programing in
> Tcl and Tk.

> Specifically, I'm working on example 12-6.

> ...

> #***** THIS IS THE PB *****#
> update
> #update idletasks ;# DOES NOT WORK
>
> after 500

> }

> Welch suggests using "update idletask" for force the geometry manager
> to redraw the screen after each interration of pack. This to show the
> effects of different anchor values.

> Well, it does not work. If you run the code with "update idle," you
> will set the variables change in the terminal window but the main
> (graphical) window will not be updated until the program exits the
> foreach loop.

Seems to work perfectly on Linux with Slackware 13.37's Tcl/Tk 8.5.9
here. And seems to perform the exact same operation with either of
"update idle" or "update".

> If you use update (a no-no, I'm hear),

For normal code, yes. For demos where you want to see the effect
change as you tweak things, it is usually not an issue. And for this
demo code, running plain "update" is no issue at all.

> Any ideas on better ways to force a refresh in this context?

I see no problems on my end running the code, so you are obviously
getting something different from what I see here.

Robert Heller

unread,
Feb 20, 2015, 3:00:27 PM2/20/15
to
The main potential problem with update vs. update idle is in event code. If
code bound to an event calls update (and not update idle), there is the
potential of a recursive call into the event loop, and that can cause
problems, since the event loop is not coded to be re-entrant. In a top-level
loop that is itself NOT in event code, there isn't (generally) any problem.

eg something this:

button .b -text {Kill me} -command {update}

Is not really a good idea -- yes, this trivial example will probably not crash
or anything, but depending on what else is going on and what other event code
is out there and what other events are being fired, this sort of code can be a
disaster waiting to happen.


>
>

--
Robert Heller -- 978-544-6933
Deepwoods Software -- Custom Software Services
http://www.deepsoft.com/ -- Linux Administration Services
hel...@deepsoft.com -- Webhosting Services

tombert

unread,
Feb 20, 2015, 3:57:00 PM2/20/15
to
I tried your script in W7, tcl85 and it works. I can see the widgets moving around each 500ms.
I always explain the difference of "update" and "update idletask" as tcl having two event queues. One for events like timer and socket like things, the other for GUI related things. "update" calls both of them, "update idletasks" only the GUI queue.
Linux and Windows do have some major differences handling the GUI. For example tcl scripts are blocked when moving a window around in Windows, in Linux the script continues execution - this is a major thing.

I do not have a iOS, but it is possible that tcl has its own idea of events on iOS.

rianmonnahan

unread,
Feb 22, 2015, 4:36:40 AM2/22/15
to
Thanks all for the replies to date. I gather that the issue is likely the way Yosemite is handling the event queues since others have been able to get the test code to work on other systems.

I understand "update" is not the appropriate way to force the GUI event handler to redraw the screen in anything other than the most trivial of programs.

The purpose of the post was to find out if there are any other ways of achieving a screen refresh. I've looked high and low.

Rich

unread,
Feb 22, 2015, 8:31:35 AM2/22/15
to
rianmonnahan <rian.m...@gmail.com> wrote:
> On Friday, February 20, 2015 at 4:50:24 PM UTC+1, rianmonnahan wrote:
> > Hi all,
> >
> > ...
> >
> > foreach anchor {center n ne e se s sw w nw center } {
> >
> > puts $anchor
> >
> > pack .foo .prop -anchor $anchor
> >
> > #***** THIS IS THE PB *****#
> > update
> > #update idletasks DOES NOT WORK
> >
> > after 500
> >
> > }
> >
> > ...

> The purpose of the post was to find out if there are any other ways
> of achieving a screen refresh. I've looked high and low.

Explicitly asking the question you really want answered in your initial
post would have helped with giving you the answer you were looking for.
The short answer is, yes, but you have to refactor the code to work in
an event driven manner.

Something like this instead of the simple foreach loop above:

proc animate {index anchors} {
set anchor [lindex $anchors $index]
puts $anchor
pack .foo .prop -anchor $anchor
set index [expr {($index + 1) % [llength $anchors]}]
if {$index != 0} {
after 500 [list animate $index $anchors]
}
}

after 500 [list animate 0 [list center n ne e se s sw w nw center]]


0 new messages