bvdp wrote: > I've just done an update to my system here to Ubuntu 11.04. Mostly no > problems ... but I have an important (to me) python/TK program that's > stopped working. Well, it works ... mostly. > > The python version is 2.7.1+ (no idea what the + means!). > > I _think_ I have traced the problem to certain menus which call a > class. The calls appear to be ignored. > > Basically, what I have is a line like: > > bf = makeButtonBar(root, row=0, column=0, buttons=( > ("Quit", self.quitall ), > ("Stop", self.stopPmidi ), > ("New Dir", self.chd), > ("Load Playlist", self.playList), > ("Favorites", selectFav), > ("Options", setOptions) ) ) > > To create a menu bar. The function makeButtonBar() creates the buttons > with: > > for txt, cmd in buttons: > Button(bf, text=txt, height=1, command=cmd).grid(column=c, > row=0, pady=5) > > > All this is fine (and worked perfectly before my upgrade). The menu > items which are ordinary functions continue to work. BUT the callbacks > which are classes are just ignored when they are clicked. > > A cut from one of the ignored classes: > > > class selectFav: > > def __init__(self): > ... > > And I've inserted some prints in the __init__() and nothing is > printed. Also, converted the class to new-style () but no change there > either. > > Either python/tk has changed or my system is totally $*(#*#. > Suggestions welcome!
Here's a minimal script to reproduces the problem: $ cat tkcallclass.py import Tkinter as tk root = tk.Tk() root.withdraw() class Classic: def __init__(self): print "hello" button = tk.Button(root, command=Classic) button.invoke() $ python2.6 tkcallclass.py hello $ python2.7 tkcallclass.py Traceback (most recent call last): File "tkcallclass.py", line 11, in <module> button.invoke() File "/usr/local/lib/python2.7/lib-tk/Tkinter.py", line 2081, in invoke return self.tk.call(self._w, 'invoke') _tkinter.TclError: invalid command name "__main__.Classic" $ In 2.7 the Tkinter code was changed to use hasattr(obj, "__call__") instead of callable(obj) to recognize callbacks. This gives different results for oldstyle classes >>> class A: pass ... >>> callable(A) True >>> hasattr(A, "__call__") False ...and they are no longer registered automatically with Tkinter. In theory you could register them explicitly yourself $ cat tkcallclass2.py import Tkinter as tk root = tk.Tk() root.withdraw() class Classic: def __init__(self): print "hello" button = tk.Button(root, command=root.register(Classic)) button.invoke() $ python2.7 tkcallclass2.py hello but in practice changing them to newstyle (i. e. have them inherit from object) or wrapping them in a lambda appears convenient. Personally, I would reconsider whether using a class as a callback is really necessary. Replacing the class with a function should be a straightforward process. -- http://mail.python.org/mailman/listinfo/python-list