TK program problem

bvdp bob at mellowood.ca
Sat May 21 20:03:12 EDT 2011


Thanks, Peter, for the detailed explanation. I was going to write a
bit of sample/minimal  code to demo this, but you nicely beat me to
it!

> 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"
> $

Any idea why I'm not getting any traceback in my program? It just runs
and appears to ignore the callback.

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

Yes, I can confirm that both the lambda and setting the class to:

    class selectFav(object):

works.

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

IIRC, I used the class method since it nicely encapsulates a set of
operations:

   - create/raise a window
   - list a set of configurable options
   - have <cancel> and <save> buttons, both of which destroy the
window.

Having a function as the callback certainly works as well. Not sure
which is the best method in the long run ... I'm trying to use classes
more in my programming since it's nice to wrap a bunch of functions up
like this.

Thanks again.




More information about the Python-list mailing list