intractable(?) Tkinter scrollbar problem
dieter at handshake.de
Sun Jun 6 06:45:21 EDT 1999
Greg McFarlane <gregm at iname.com> writes on Mon, 31 May 1999 14:10:54 GMT:
> I include a Tkinter script below, modified from one by Mark C Favas,
> using, I believe, Fredrik Lundh's AutoScrollbar class. When this
> script is run, the two scrollbars continuously get mapped and unmapped
> and the window continuously changes size.
I think, I now understand the instability and I should have
When the grid is changed in "AutoScrollbar.set",
Tk initiates two waves that propagate this information.
The waves are initiated and propagated through
One wave goes upward towards the top level. Once
the top level is reached, the window manager is told
to adjust the toplevel size. Tk waits locally
for a ConfigureNotify event, telling that the
update is completed.
Then, "Tcl_DoWhenIdle(UpdateGeometryInfo,...)" initiates
a new wave down towards the "scrollFrame" informing
about the new window geometry. This wave, too,
is propagated through successive "Tcl_DoWhenIdle(ArrangeGrid,...)
In some sense, the wave from the grid change is reflected
at the top level and now goes back towards the scrollFrame.
The second wave goes downward towards the grid slaves.
When it reaches the canvas, "CanvasUpdateScrollbars"
is called in "DisplayCanvas" which in turn calls
At this time, the toplevel has already been adjusted
and the wave informing about the change is going downward,
but it is behind the first downward wave.
Based on the outdated information, a new grid change
is performed, resulting again in two waves upward
Shortly later, the geometry propagation wave from
the toplevel reaches the canvas. In "CanvasUpdateScrollbars",
the grid structure is changed a third time,
two new waves are initiated ....
We must prevent the first downward wave to do bad
things before the upward (and eventually reflected)
wave has reached the canvas.
The following code should do this:
def set(self, lo, hi):
self.lo= lo; self.hi= hi
#if self._active: print 'active'; return
self._active= 1; self.update_idletasks(); self._active= 0
lo= self.lo; hi= self.hi
#print self.id, lo, hi
if float(lo) <= 0.0 and float(hi) >= 1.0:
self.tk.call("grid", "remove", self)
Tkinter.Scrollbar.set(self, lo, hi)
The first wave downward reaches the canvas and there
It sets "_active=1" and then waits in "update_idletasks"
for the arrival of the reflected wave.
When the reflected wave reaches the canvas, it provides
new updated values for "lo" and "hi".
It then sees the "_active == 1" and returns.
The first wave takes over and updates the grid
with up to date "lo" and "hi" values.
"update_idletasks" is a powerful mechanism of which the use
may have nasty side effects.
For example, it may result in flickering.
However, this is probably better than the instability,
More information about the Python-list