Tkinter and clone widgets

Eric Pettersen pett at address.is.in.sig
Tue Feb 1 04:01:34 CET 2000


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

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
this:

.#5372422832#5374429664.#5372422832#5374429664#5374866736.#5372422832#5374429
664#5374866736#5373451424.#5372422832#5374429664#5374866736#5373451424#537487
1536

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
clause.

*** Tkinter.py  Fri Jan 21 16:03:47 2000
--- Tkinter.py.orig     Fri Jan 21 15:45:02 2000
***************
*** 532,550 ****
                                name, tail = name[:i], name[i+1:]
                        else:
                                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:]
                        else:
                                tail = ''
!                       w = w.children[name]
                        name = tail
                return w
        _nametowidget = nametowidget

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



More information about the Python-list mailing list