Tk Source Code

View Ticket
Bounty program for improvements to Tcl and certain Tcl packages.
Ticket UUID: 2863003
Title: Add a virtual event when GM leaves parent without slaves
Type: Patch Version: None
Submitter: egavilan Created on: 2009-09-20 23:41:29
Subsystem: 48. Geometry Management Assigned To: pspjuth
Priority: 6 Severity: Minor
Status: Closed Last Modified: 2020-12-09 12:00:42
Resolution: Fixed Closed By: oehhar
    Closed on: 2020-12-09 12:00:42
When trying to build a custom scrolledframe one generally resorts to the <Configure> event to catch the resizing of the scrolled frame [usually a frame inside a canvas] to keep scrollbars in sync. The problem with this approach is that, when the last slave is removed from inside the frame, the geometry managers leave the frame size as-is, and the scrolled frame ends scrolling an empty region.
This can be noted in this BWidget example:
package require BWidget

set sw [ScrolledWindow .sw]
set sf [ScrollableFrame .sf]
$sw setwidget $sf
set f [$sf getframe]

pack $sw -expand 1 -fill both -padx 10 -pady 10

for {set i 0} {$i <= 20} {incr i} {
grid \
[label $$i -text "Label a order $i"] \
[label $$i -text "Label b order $i"] \
[label $$i -text "Label c order $i"]

after 5000 {destroy {*}[winfo children $sf]}

A way to note when the GM removes the last slave is to deliver a virtual event to the master.
This patch adds the virtual event, and is intended as a sketch of the final code (the name of the
virtual event, and whether to send additional details or not can be changed)
User Comments: oehhar added on 2018-09-23 08:28:38:

I had forgotten to merge trunk.

With the now trunk merged version [1ab46e2b1d187f4c], the sample in the wiki works.

Sorry, Harald

oehhar added on 2018-09-22 20:36:22:

New TIP 518 proposes the solution by Emiliano.

Unfortunately, the updated solution in does not work for me. More precisely, the example in the TIP does not fire the new virtual event for me.

Strange, I tested Emilianos code before and it worked. It must be my issue...


oehhar added on 2016-11-07 07:55:55:

TIP#454 was voted pass but will be rejected du to issues described in ticket [d6b95ce4].

So the solution described here and in the branch [60230550] with the tags [rfe-2863003fff] may be followed in future.

Thank you all for participating, Harald

oehhar added on 2016-10-22 17:11:11:

May be emultaed by accepted TIP 454 (see also ticket [d6b95ce4]), by a configure binding.

I propose to close this issue.

Thanks, Harald

emiliano added on 2016-09-22 13:41:34:
Attached demo code. The relevant part is on line 27

emiliano added on 2016-09-22 12:20:41:
For the record, Tk never requires a width or height of 0, the minimum is 1.
A newly created frame (or ttk::frame) has a configured width of 0, but a
required width of 1

(Desktop) 1 % package require Tk
(Desktop) 2 % frame .f
(Desktop) 3 % puts [.f cget -width]\ [winfo reqwidth .f]
0 1

So, to restore the original state of a frame after the geometry manager
leaves the master without managed widgets, you have to configure
the frame twice

(Desktop) 4 % pack [label .f.l -text hello]; event generate .f.l <Expose> ; update idle; destroy .f.l
(Desktop) 5 % puts [.f cget -width]\ [winfo reqwidth .f]
0 32
(Desktop) 6 % .f configure -width 1; .f configure -width 0
(Desktop) 7 % puts [.f cget -width]\ [winfo reqwidth .f]
0 1

Note that if you directly configure the width to 0, it will have no effect
since that's the already configured width so it becomes a no-op.

oehhar added on 2016-09-21 07:15:11:

Grid works also as expected:

% pack [frame .c]
% bind .c <<GeometryManager>> {puts *}
% grid [entry .c.e]
% grid forget .c.e

oehhar added on 2016-09-21 07:13:07:

Thanks to Francois to put this in a branch in commit [60230550] with the tags [rfe-2863003fff], [d6b95ce492].

This is linked to solve the frame issue in ticket [d6b95ce4].

I have tested the branch as follows:

% pack [frame .c]
% pack [entry .c.e]
% pack forget .c.e
% bind .c <<GeometryManager>> {puts *}
% pack .c.e
% pack forget .c.e

So it deliveres a virtual event when the last children is unmapped.

Then I tried to invoke the workaround to shring the window to 1 pixel (not 0), which works as expected:

% pack [frame .c]
% bind .c <<GeometryManager>> "%W configure -height 1;%W configure -height 0"
% pack [entry .c.e]
% # toplevel only shows the entry
% pack forget .c.e
% # toplevel shows a frame of 1 pixel in height

I have no idea, how to write a script to restore the initial state that the frame has 0 height.

hobbs added on 2009-09-22 03:56:36:
It is the master becoming empty, which otherwise passes no events (not even <Configure>), so Tcl-based gms like scrollableframe can't shrink accordingly.  There are possibly other vevents that would make sense to generate to get rid of the reliance on <Configure> in so many apps.

pspjuth added on 2009-09-22 01:42:29:
If it is the fact that a master gets empty that is important, or that it becomes
If the latter, maybe the event should reside in the recently added
TkFreeGeometryMaster which gets called regardless what is causing it
to become unmanaged..

egavilan added on 2009-09-21 06:59:38:
Forgot to mention, patch's code is copied almost literally from the GenerateModifiedEvent() function in generic/tkText.c

egavilan added on 2009-09-21 06:41:29:
File Added - 343719: geometry.diff