Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #5867 > unrolled thread

TK program problem

Started bybvdp <bob@mellowood.ca>
First post2011-05-20 11:03 -0700
Last post2011-05-23 00:25 +1000
Articles 16 — 6 participants

Back to article view | Back to comp.lang.python


Contents

  TK program problem bvdp <bob@mellowood.ca> - 2011-05-20 11:03 -0700
    Re: TK program problem Ian Kelly <ian.g.kelly@gmail.com> - 2011-05-20 13:20 -0600
      Re: TK program problem bvdp <bob@mellowood.ca> - 2011-05-20 15:12 -0700
        Re: TK program problem Ian Kelly <ian.g.kelly@gmail.com> - 2011-05-20 16:33 -0600
          Re: TK program problem bvdp <bob@mellowood.ca> - 2011-05-20 16:07 -0700
            Re: TK program problem Ian Kelly <ian.g.kelly@gmail.com> - 2011-05-20 17:29 -0600
              Re: TK program problem bvdp <bob@mellowood.ca> - 2011-05-20 16:34 -0700
            Re: TK program problem rantingrick <rantingrick@gmail.com> - 2011-05-20 16:37 -0700
              Re: TK program problem bvdp <bob@mellowood.ca> - 2011-05-21 17:07 -0700
    Re: TK program problem Peter Otten <__peter__@web.de> - 2011-05-21 10:18 +0200
      Re: TK program problem bvdp <bob@mellowood.ca> - 2011-05-21 17:03 -0700
        Re: TK program problem Terry Reedy <tjreedy@udel.edu> - 2011-05-21 20:33 -0400
          Re: TK program problem bvdp <bob@mellowood.ca> - 2011-05-21 19:20 -0700
            Re: TK program problem Terry Reedy <tjreedy@udel.edu> - 2011-05-22 17:17 -0400
        Re: TK program problem rantingrick <rantingrick@gmail.com> - 2011-05-22 07:03 -0700
          Re: TK program problem Chris Angelico <rosuav@gmail.com> - 2011-05-23 00:25 +1000

#5867 — TK program problem

Frombvdp <bob@mellowood.ca>
Date2011-05-20 11:03 -0700
SubjectTK program problem
Message-ID<9f91909a-ce08-47dd-81d3-e7cf2edad3b6@h12g2000pro.googlegroups.com>
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!

[toc] | [next] | [standalone]


#5874

FromIan Kelly <ian.g.kelly@gmail.com>
Date2011-05-20 13:20 -0600
Message-ID<mailman.1857.1305919249.9059.python-list@python.org>
In reply to#5867
On Fri, May 20, 2011 at 12:03 PM, bvdp <bob@mellowood.ca> wrote:
> 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.

I'm not a tk user, but it sounds like it has regressed from accepting
arbitrary callables as callbacks to accepting functions specifically.

What happens if you replace:

("Favorites", selectFav),

with:

("Favorites", lambda: selectFav()),

[toc] | [prev] | [next] | [standalone]


#5885

Frombvdp <bob@mellowood.ca>
Date2011-05-20 15:12 -0700
Message-ID<10f0acf7-b63b-4cf3-949b-5d0caba19fb0@z13g2000prk.googlegroups.com>
In reply to#5874
> I'm not a tk user, but it sounds like it has regressed from accepting
> arbitrary callables as callbacks to accepting functions specifically.
>
> What happens if you replace:
>
> ("Favorites", selectFav),
>
> with:
>
> ("Favorites", lambda: selectFav()),

Okay, this works. Great and thanks! Seems to me that the way I was
doing it should be alright ... and I've got some other programs
exhibiting the same problem.

Before I go "fixing" the issue ... is this known or even a bug?

[toc] | [prev] | [next] | [standalone]


#5886

FromIan Kelly <ian.g.kelly@gmail.com>
Date2011-05-20 16:33 -0600
Message-ID<mailman.1864.1305930866.9059.python-list@python.org>
In reply to#5885
On Fri, May 20, 2011 at 4:12 PM, bvdp <bob@mellowood.ca> wrote:
> Okay, this works. Great and thanks! Seems to me that the way I was
> doing it should be alright ... and I've got some other programs
> exhibiting the same problem.
>
> Before I go "fixing" the issue ... is this known or even a bug?

The docs [1] say that a callback is a function, so I guess that if it
worked before it was just luck.  You should bring it up on the tkinter
list and see what they have to say about it, though.

I'm a bit confused about why you would want to use a class as a
callback anyway.  It looks like when the button is clicked it
instantiates the class and then throws it away?

[1] http://docs.python.org/library/tkinter.html#tk-option-data-types

[toc] | [prev] | [next] | [standalone]


#5888

Frombvdp <bob@mellowood.ca>
Date2011-05-20 16:07 -0700
Message-ID<a20a9805-5f61-4112-a5b2-a7685eea7063@18g2000prd.googlegroups.com>
In reply to#5886
Probably the fix is to use a function :)

> The docs [1] say that a callback is a function, so I guess that if it
> worked before it was just luck.  You should bring it up on the tkinter
> list and see what they have to say about it, though.
>
> I'm a bit confused about why you would want to use a class as a
> callback anyway.  It looks like when the button is clicked it
> instantiates the class and then throws it away?

I have no idea why I used a class like this, expect that it seemed to
work at the time. Yes, the class is instantiated when the button is
clicked. Then, the user stays in the class and uses its methods until
he hits <close> in the class.

So, I guess what's happening is that I'm treating the button click
much like a call to a new program/window which sets some options, etc.
in the main program.

You mention the tkinter group. Ummm, what group is that???

Best,

[toc] | [prev] | [next] | [standalone]


#5889

FromIan Kelly <ian.g.kelly@gmail.com>
Date2011-05-20 17:29 -0600
Message-ID<mailman.1867.1305934179.9059.python-list@python.org>
In reply to#5888
On Fri, May 20, 2011 at 5:07 PM, bvdp <bob@mellowood.ca> wrote:
> You mention the tkinter group. Ummm, what group is that???

http://tkinter.unpythonic.net/wiki/TkinterDiscuss

[toc] | [prev] | [next] | [standalone]


#5890

Frombvdp <bob@mellowood.ca>
Date2011-05-20 16:34 -0700
Message-ID<d85d06d3-09aa-4508-8924-83e4b2b85d13@18g2000prd.googlegroups.com>
In reply to#5889
On May 20, 4:29 pm, Ian Kelly <ian.g.ke...@gmail.com> wrote:
> On Fri, May 20, 2011 at 5:07 PM, bvdp <b...@mellowood.ca> wrote:
> > You mention the tkinter group. Ummm, what group is that???
>
> http://tkinter.unpythonic.net/wiki/TkinterDiscuss

Thanks. New one for me. I'll subscribe and see if they know about
this.

Best,

[toc] | [prev] | [next] | [standalone]


#5891

Fromrantingrick <rantingrick@gmail.com>
Date2011-05-20 16:37 -0700
Message-ID<136b3435-a6bd-45fa-9c8c-5602ea23c861@s2g2000yql.googlegroups.com>
In reply to#5888
On May 20, 6:07 pm, bvdp <b...@mellowood.ca> wrote:
> Probably the fix is to use a function :)
>
> > The docs [1] say that a callback is a function, so I guess that if it
> > worked before it was just luck.  You should bring it up on the tkinter
> > list and see what they have to say about it, though.
>
> > I'm a bit confused about why you would want to use a class as a
> > callback anyway.  It looks like when the button is clicked it
> > instantiates the class and then throws it away?
>
> I have no idea why I used a class like this, expect that it seemed to
> work at the time. Yes, the class is instantiated when the button is
> clicked. Then, the user stays in the class and uses its methods until
> he hits <close> in the class.

Thats sounds to me a lot like hammering square pegs though round
holes... Perhaps you should explain first in "plain english" what
problem your application is intended to solve, then how it is expected
to interact with the user, and finally, what exactly is NOT working
correctly. I would suffix such a documentary with the current source
code, verbatim.

[toc] | [prev] | [next] | [standalone]


#5942

Frombvdp <bob@mellowood.ca>
Date2011-05-21 17:07 -0700
Message-ID<ea980875-ac49-4563-a7c8-5b4683341bda@k27g2000pri.googlegroups.com>
In reply to#5891
On May 20, 4:37 pm, rantingrick <rantingr...@gmail.com> wrote:

> Thats sounds to me a lot like hammering square pegs though round
> holes... Perhaps you should explain first in "plain english" what

Ahh, but what fun would the Internet, Usenet and programming be
without round holes and square pegs.

I thought my English was pretty good.

> problem your application is intended to solve, then how it is expected

I'm trying very much to focus on the problem I'm having with a
particular bit of python code. I'm not trying to have the community
solve my coding problems.

> to interact with the user, and finally, what exactly is NOT working
> correctly. I would suffix such a documentary with the current source
> code, verbatim.

You want me to attach several hundred/thousand lines of source code to
demonstrate that a particular bit of python has changed behavior
between versions?

[toc] | [prev] | [next] | [standalone]


#5905

FromPeter Otten <__peter__@web.de>
Date2011-05-21 10:18 +0200
Message-ID<ir7shb$dd8$1@solani.org>
In reply to#5867
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.

[toc] | [prev] | [next] | [standalone]


#5941

Frombvdp <bob@mellowood.ca>
Date2011-05-21 17:03 -0700
Message-ID<fe3b6da7-4e9a-4226-bc6e-a271714c2df8@e17g2000prj.googlegroups.com>
In reply to#5905
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.

[toc] | [prev] | [next] | [standalone]


#5944

FromTerry Reedy <tjreedy@udel.edu>
Date2011-05-21 20:33 -0400
Message-ID<mailman.1891.1306024415.9059.python-list@python.org>
In reply to#5941
On 5/21/2011 8:03 PM, bvdp wrote:

> Yes, I can confirm that both the lambda and setting the class to:
>
>      class selectFav(object):

One of the purposes and advantages of Python 3 is having only one class 
system. Best to always use new-style classes in Python 2.2+ unless you 
understand and need old-style classes (and need should be never for most 
people).

-- 
Terry Jan Reedy.

[toc] | [prev] | [next] | [standalone]


#5948

Frombvdp <bob@mellowood.ca>
Date2011-05-21 19:20 -0700
Message-ID<42561028-39ce-4543-8e3c-b021e3a2b067@34g2000pru.googlegroups.com>
In reply to#5944
> One of the purposes and advantages of Python 3 is having only one class
> system. Best to always use new-style classes in Python 2.2+ unless you
> understand and need old-style classes (and need should be never for most
> people).
>

Thanks for this. I'll keep it in mind!

One thing I really don't understand ... is there a difference between
the old/new forms:

   class foo:
   class foo():

In cases where I've played with them, they _appear_ to work the same?
Also, where does one find the magic that says that for a tkinter class
you should use:

   class foo(object):

Not really sure where "object" comes from.

Thanks and best,

[toc] | [prev] | [next] | [standalone]


#6008

FromTerry Reedy <tjreedy@udel.edu>
Date2011-05-22 17:17 -0400
Message-ID<mailman.1930.1306099067.9059.python-list@python.org>
In reply to#5948
On 5/21/2011 10:20 PM, bvdp wrote:
>
>> One of the purposes and advantages of Python 3 is having only one class
>> system. Best to always use new-style classes in Python 2.2+ unless you
>> understand and need old-style classes (and need should be never for most
>> people).
>>
>
> Thanks for this. I'll keep it in mind!
>
> One thing I really don't understand ... is there a difference between
> the old/new forms:
>
>     class foo:
>     class foo():
>
> In cases where I've played with them, they _appear_ to work the same?

I believe they are. Same is true in 3.x except that the result in a 
new-style class.

> Also, where does one find the magic that says that for a tkinter class
> you should use:
>
>     class foo(object):

Perhaps nowhere. It may have been an unintended side-effect of the 
change in callable check, or intentional but not documented.

> Not really sure where "object" comes from.

It is the base class of all (new-style) classes.
 >>> object()
<object object at 0x00EB6668>

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#5975

Fromrantingrick <rantingrick@gmail.com>
Date2011-05-22 07:03 -0700
Message-ID<5a309bd1-71e1-4c78-a304-24552b1c5da5@m40g2000vbt.googlegroups.com>
In reply to#5941
On May 21, 7:03 pm, bvdp <b...@mellowood.ca> wrote:
> 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.

Ok NOW we are getting somewhere! It is amazing how helpful people can
be when you explain your problem in "plain English". What you are
describing here is a dialog (be it modal or not). However your earlier
description of...

 """Yes, the class is instantiated when the button is clicked. Then,
the user stays in the class and uses its methods until he hits <close>
in the class. """

... was about as effective as the "orb of confusion" on Patrick...
*drool*

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

Yes you ABSOLUTELY SHOULD encapsulate the dialog code in a class! THEN
create an instance of the class inside a "easy to call" function.

class MyDialog(blah):
   blah,blah,blah

def show_dialog(*args):
    d = MyDialog(*args)
    return d.result

result = show_dialog()

...and they all lived happily ever after ;-)

[toc] | [prev] | [next] | [standalone]


#5976

FromChris Angelico <rosuav@gmail.com>
Date2011-05-23 00:25 +1000
Message-ID<mailman.1915.1306074309.9059.python-list@python.org>
In reply to#5975
On Mon, May 23, 2011 at 12:03 AM, rantingrick <rantingrick@gmail.com> wrote:
> ... was about as effective as the "orb of confusion" on Patrick...
> *drool*
>

That sounds like a Dungeons and Dragons artifact item... invoking the
orb of confusion is a standard action that does not provoke an Attack
of Opportunity.

> class MyDialog(blah):
>   blah,blah,blah
>
> def show_dialog(*args):
>    d = MyDialog(*args)
>    return d.result
>
> result = show_dialog()

I don't really see why it shouldn't be valid to use the class itself
in this way. Once the constructor returns, the object IS the return
value.

But then, my opinion may not be valid. I've done weird things in C++
where, for instance, the invocation of a modeless dialog is:

new FoobarDialog(params);

And somewhere it has an event (eg when the window is destroyed) that executes:

delete this;

I'm a little mad and generally silly, so my opinion doesn't matter
(matter matter matter matter). But it did work, and the code was nice
and clean!

Chris Angelico

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web