Tkinter and clone widgets

Eric Pettersen pett at
Tue Feb 1 04:01:34 CET 2000

I came up with a mod to to handle Tk clone widgets that I
thought I'd run by the wizened sages of the group to see if it seemed

As a quick review, when you use the "menu=" option of a Toplevel to set
the window menubar, Tk clones your menu hierarchy and uses these clones
to form the menubar, rather than using your original menu hierarchy.
Changes to the original hierarchy are reflected in the clone hierarchy,
and choosing menu items in the clone hierarchy cause the appropriate
original callbacks to get fired.  The problem is if you are trying to use
Tkinter to bind other event handlers to these widgets (e.g. balloon help),
since the clone widget name that Tkinter receives from Tk isn't properly
resolved to the Menu instance.

However, the clone menu name can be fairly easily parsed to extract the
name of the corresponding original menu.  A clone widget name looks like


Yes, it is indeed butt-ugly.

The rules used to construct clone widget names seem to be undocumented
(please correct me if I'm mistaken), but seem to be:

1) the name is dot-separated like a normal widget name (and starts with
a dot)

2) each name component corresponds to a clone widget, with the first being
the menubar and successive components corresponding to increasingly deeper
nested child clone widgets

3) The name components are each like a normal full widget names with hashes
('#') instead of dots ('.'), and the hash-separated components correspond
to their "real" (non-cloned) widgets.

So, it's possible to find the Tkinter Menu instance from the clone name
by looking at the last dot-separated name component, change the hashes to
dots, and then look that up as if it were a normal widget name.  The change
to Tkinter to do that is appended below.  Essentially, it changes the "w
= w.children[name]" statement of the nametowidget function into a try/except

***  Fri Jan 21 16:03:47 2000
---     Fri Jan 21 15:45:02 2000
*** 532,550 ****
                                name, tail = name[:i], name[i+1:]
                                tail = ''
!                       try:
!                               w = w.children[name]
!                       except KeyError:
!                               if name[0] == '#':
!                                       # looks like clone widget...
!                                       if not tail:
!                                               tail = name
!                                       lastDot = _string.rfind(tail, '.')
!                                       if lastDot >= 0:
!                                               tail = tail[lastDot+1:]
!                                       clone = _string.replace(tail, '#', 
!                                       return self.nametowidget(clone)
!                               raise
                        name = tail
                return w
        _nametowidget = nametowidget
--- 532,538 ----
                                name, tail = name[:i], name[i+1:]
                                tail = ''
!                       w = w.children[name]
                        name = tail
                return w
        _nametowidget = nametowidget

		Eric Pettersen
		pett "at" cgl "dot" ucsf "dot" edu (NeXTmail capable)

More information about the Python-list mailing list