main window in tkinter app

Discussion in 'Python' started by William Gill, Jul 18, 2005.

  1. William Gill

    William Gill Guest

    A short while ago someone posted that(unlike the examples) you should
    use Tk as the base for your main window in tkinter apps, not Frame. Thus :

    class MyMain(Frame):
    def __init__(self, master):
    self.root = master
    self.master=master
    self.createWidgets()
    def createWidgets():
    ...
    root = Tk()
    app = MyMain(root)
    app.master.title("Object Editor")
    root.mainloop()

    would become:

    class MyMain(Tk):
    ...
    ...
    app = MyMain()
    app.title("My App")
    app.mainloop()

    When I try converting to this approach I run into a problem with the
    __init__() method. It appears to go into an infinite loop in
    tkinter.__getattr__().

    If I omit __init__() I get a properly titled window, but must explicitly
    call my createWidgets method from __main__.

    class MyMain(Tk):
    createWidgets()
    ...
    ...

    app = MyMain()
    app.title("My App")
    app.createWidgets()
    app.mainloop()

    Am I missing something?

    Bill
     
    William Gill, Jul 18, 2005
    #1
    1. Advertising

  2. William Gill

    Eric Brunel Guest

    On Mon, 18 Jul 2005 16:57:51 GMT, William Gill <> wrote:

    > A short while ago someone posted that(unlike the examples) you should
    > use Tk as the base for your main window in tkinter apps, not Frame. Thus :
    >
    > class MyMain(Frame):
    > def __init__(self, master):
    > self.root = master
    > self.master=master
    > self.createWidgets()
    > def createWidgets():
    > ...
    > root = Tk()
    > app = MyMain(root)
    > app.master.title("Object Editor")
    > root.mainloop()
    >
    > would become:
    >
    > class MyMain(Tk):
    > ...
    > ...
    > app = MyMain()
    > app.title("My App")
    > app.mainloop()
    >
    > When I try converting to this approach I run into a problem with the
    > __init__() method. It appears to go into an infinite loop in
    > tkinter.__getattr__().

    [...]

    I never ran into this problem. Can you please post a short script showing this behavior? Without knowing what you exactly do in your __init__ and createWidgets method, it's quite hard to figure out what happens...
    --
    python -c "print ''.join([chr(154 - ord(c)) for c in 'U(17zX(%,5.zmz5(17;8(%,5.Z65\'*9--56l7+-'])"
     
    Eric Brunel, Jul 19, 2005
    #2
    1. Advertising

  3. William Gill

    William Gill Guest

    > I never ran into this problem. ...

    O.K. That, means I probably have something else wrong. I will need to
    start with a 'clean slate' instead of trying to modify existing code.
    It's getting to convoluted to follow anyway after all the cobbling I've
    done.

    If I get a repeat of the original problem I will post the code and the
    exact error message, but at least now I know It SHOULD work.

    Thanks

    Bill,


    Eric Brunel wrote:
    > On Mon, 18 Jul 2005 16:57:51 GMT, William Gill <> wrote:
    >
    >> A short while ago someone posted that(unlike the examples) you should
    >> use Tk as the base for your main window in tkinter apps, not Frame.
    >> Thus :
    >>
    >> class MyMain(Frame):
    >> def __init__(self, master):
    >> self.root = master
    >> self.master=master
    >> self.createWidgets()
    >> def createWidgets():
    >> ...
    >> root = Tk()
    >> app = MyMain(root)
    >> app.master.title("Object Editor")
    >> root.mainloop()
    >>
    >> would become:
    >>
    >> class MyMain(Tk):
    >> ...
    >> ...
    >> app = MyMain()
    >> app.title("My App")
    >> app.mainloop()
    >>
    >> When I try converting to this approach I run into a problem with the
    >> __init__() method. It appears to go into an infinite loop in
    >> tkinter.__getattr__().

    >
    > [...]
    >
    > I never ran into this problem. Can you please post a short script
    > showing this behavior? Without knowing what you exactly do in your
    > __init__ and createWidgets method, it's quite hard to figure out what
    > happens...
     
    William Gill, Jul 19, 2005
    #3
  4. William Gill

    William Gill Guest

    O.K. I tried from scratch, and the following snippet produces an
    infinite loop saying:

    File "C:\Python24\lib\lib-tk\Tkinter.py", line 1647, in __getattr__
    return getattr(self.tk, attr)

    If I comment out the __init__ method, I get the titled window, and print
    out self.var ('1')


    import os
    from Tkinter import *

    class MyApp(Tk):
    var=1
    def __init__(self):
    pass
    def getval(self):
    return self.var


    app = MyApp()

    app.title("An App")
    print app.getval()
    app.mainloop()


    Eric Brunel wrote:
    > On Mon, 18 Jul 2005 16:57:51 GMT, William Gill <> wrote:
    >
    >> A short while ago someone posted that(unlike the examples) you should
    >> use Tk as the base for your main window in tkinter apps, not Frame.
    >> Thus :
    >>
    >> class MyMain(Frame):
    >> def __init__(self, master):
    >> self.root = master
    >> self.master=master
    >> self.createWidgets()
    >> def createWidgets():
    >> ...
    >> root = Tk()
    >> app = MyMain(root)
    >> app.master.title("Object Editor")
    >> root.mainloop()
    >>
    >> would become:
    >>
    >> class MyMain(Tk):
    >> ...
    >> ...
    >> app = MyMain()
    >> app.title("My App")
    >> app.mainloop()
    >>
    >> When I try converting to this approach I run into a problem with the
    >> __init__() method. It appears to go into an infinite loop in
    >> tkinter.__getattr__().

    >
    > [...]
    >
    > I never ran into this problem. Can you please post a short script
    > showing this behavior? Without knowing what you exactly do in your
    > __init__ and createWidgets method, it's quite hard to figure out what
    > happens...
     
    William Gill, Jul 19, 2005
    #4
  5. William Gill

    William Gill Guest

    It also seems to operate the same with or without " app.mainloop()". Is
    an explicit call to mainloop needed?

    William Gill wrote:
    > O.K. I tried from scratch, and the following snippet produces an
    > infinite loop saying:
    >
    > File "C:\Python24\lib\lib-tk\Tkinter.py", line 1647, in __getattr__
    > return getattr(self.tk, attr)
    >
    > If I comment out the __init__ method, I get the titled window, and print
    > out self.var ('1')
    >
    >
    > import os
    > from Tkinter import *
    >
    > class MyApp(Tk):
    > var=1
    > def __init__(self):
    > pass
    > def getval(self):
    > return self.var
    >
    >
    > app = MyApp()
    >
    > app.title("An App")
    > print app.getval()
    > app.mainloop()
    >
    >
    > Eric Brunel wrote:
    >
    >> On Mon, 18 Jul 2005 16:57:51 GMT, William Gill <>
    >> wrote:
    >>
    >>> A short while ago someone posted that(unlike the examples) you should
    >>> use Tk as the base for your main window in tkinter apps, not Frame.
    >>> Thus :
    >>>
    >>> class MyMain(Frame):
    >>> def __init__(self, master):
    >>> self.root = master
    >>> self.master=master
    >>> self.createWidgets()
    >>> def createWidgets():
    >>> ...
    >>> root = Tk()
    >>> app = MyMain(root)
    >>> app.master.title("Object Editor")
    >>> root.mainloop()
    >>>
    >>> would become:
    >>>
    >>> class MyMain(Tk):
    >>> ...
    >>> ...
    >>> app = MyMain()
    >>> app.title("My App")
    >>> app.mainloop()
    >>>
    >>> When I try converting to this approach I run into a problem with the
    >>> __init__() method. It appears to go into an infinite loop in
    >>> tkinter.__getattr__().

    >>
    >>
    >> [...]
    >>
    >> I never ran into this problem. Can you please post a short script
    >> showing this behavior? Without knowing what you exactly do in your
    >> __init__ and createWidgets method, it's quite hard to figure out what
    >> happens...
     
    William Gill, Jul 19, 2005
    #5
  6. William Gill wrote:
    > O.K. I tried from scratch, and the following snippet produces an
    > infinite loop saying:
    >
    > File "C:\Python24\lib\lib-tk\Tkinter.py", line 1647, in __getattr__
    > return getattr(self.tk, attr)
    >
    > If I comment out the __init__ method, I get the titled window, and print
    > out self.var ('1')
    >
    >
    > import os
    > from Tkinter import *
    >
    > class MyApp(Tk):
    > var=1
    > def __init__(self):
    > pass
    > def getval(self):
    > return self.var
    >
    >
    > app = MyApp()
    >
    > app.title("An App")
    > print app.getval()
    > app.mainloop()


    You're not calling the parent's __init__ inside your derived class. I
    would point out where the Python Tutorial points out that you should do
    this, but it's not in the obvious place (Classes: Inheritance).

    Python does -not- automagically call parent-class __init__s for derived
    classes, you must do that explicitly. Changing the definition of your
    class to the following works:
    >>> class MyApp(Tk):

    var=1
    def __init__(self):
    Tk.__init__(self)
    pass
    def getval(self):
    return self.var

    It works when you comment out __init__ because of a quirk in Python's
    name resolution. As you'd logically expect, if you don't define a
    function in a derived class but call it (such as instance.method()), it
    will call the method from the base class.

    You just proved that this works for __init__ methods also. When you
    didn't define __init__ for your derived class, MyApp() called
    Tk.__init__(), which Does the Right Thing in terms of setting up all the
    specific Tkinter-specific members.
     
    Christopher Subich, Jul 20, 2005
    #6
  7. William Gill

    William Gill Guest

    That does it!, thanks.

    Thinking about it, when I created a derived class with an __init__
    method, I overrode the base class's init. It should have been
    intuitive that I needed to explicitly call baseclass.__init(self), it
    wasn't. It might have hit me if the fault was related to someting in
    baseclass.__init() not taking place, but the recursion loop didn't give
    me a clue. Any idea why failing to init the base class caused the loop?


    Bill


    Christopher Subich wrote:
    > William Gill wrote:
    >
    >> O.K. I tried from scratch, and the following snippet produces an
    >> infinite loop saying:
    >>
    >> File "C:\Python24\lib\lib-tk\Tkinter.py", line 1647, in __getattr__
    >> return getattr(self.tk, attr)
    >>
    >> If I comment out the __init__ method, I get the titled window, and
    >> print out self.var ('1')
    >>
    >>
    >> import os
    >> from Tkinter import *
    >>
    >> class MyApp(Tk):
    >> var=1
    >> def __init__(self):
    >> pass
    >> def getval(self):
    >> return self.var
    >>
    >>
    >> app = MyApp()
    >>
    >> app.title("An App")
    >> print app.getval()
    >> app.mainloop()

    >
    >
    > You're not calling the parent's __init__ inside your derived class. I
    > would point out where the Python Tutorial points out that you should do
    > this, but it's not in the obvious place (Classes: Inheritance).
    >
    > Python does -not- automagically call parent-class __init__s for derived
    > classes, you must do that explicitly. Changing the definition of your
    > class to the following works:
    > >>> class MyApp(Tk):

    > var=1
    > def __init__(self):
    > Tk.__init__(self)
    > pass
    > def getval(self):
    > return self.var
    >
    > It works when you comment out __init__ because of a quirk in Python's
    > name resolution. As you'd logically expect, if you don't define a
    > function in a derived class but call it (such as instance.method()), it
    > will call the method from the base class.
    >
    > You just proved that this works for __init__ methods also. When you
    > didn't define __init__ for your derived class, MyApp() called
    > Tk.__init__(), which Does the Right Thing in terms of setting up all the
    > specific Tkinter-specific members.
     
    William Gill, Jul 20, 2005
    #7
  8. William Gill wrote:
    > That does it!, thanks.
    >
    > Thinking about it, when I created a derived class with an __init__
    > method, I overrode the base class's init. It should have been
    > intuitive that I needed to explicitly call baseclass.__init(self), it
    > wasn't. It might have hit me if the fault was related to someting in
    > baseclass.__init() not taking place, but the recursion loop didn't give
    > me a clue. Any idea why failing to init the base class caused the loop?


    You never pasted the first part of the traceback:

    File "<pyshell#204>", line 1, in -toplevel-
    app.title('frob')
    File "C:\Python24\Lib\lib-tk\Tkinter.py", line 1531, in wm_title
    return self.tk.call('wm', 'title', self._w, string)
    File "C:\Python24\Lib\lib-tk\Tkinter.py", line 1654, in __getattr__
    return getattr(self.tk, attr)
    File "C:\Python24\Lib\lib-tk\Tkinter.py", line 1654, in __getattr__
    return getattr(self.tk, attr)

    When you didn't call Tk.__init__(self), self.tk was never initialized.
    Further, it's obvious from the traceback that Tk implements a
    __getattr__ method; from the python docs:

    __getattr__(self,name): Called when an attribute lookup has not found
    the attribute in the usual places

    Since self.tk doesn't exist, __getattr__(self,tk) was called. Without
    looking at the TKinter source code, we can surmise that there's a
    default behavior of "if self doesn't have it, return the relevant
    attribute from within self.tk." The problem, of course, arises when
    self.tk doesn't exist -- this causes the self.tk reference to call
    self.__getattr__('tk'), which is recursive.

    The infinite recursion, then, is a mild bug in TKinter that doesn't show
    itself during normal use. The proper solution should be to replace the
    self.tk call with either self.__dict__['tk'], or to make Tk a new-style
    class and use object.__getattribute__(self,'tk'). (Note: there are
    probably some fine details that I'm missing in this 'solution', so take
    it with a potato-sized grain of salt. The general principle still
    applies though.)
     
    Christopher Subich, Jul 20, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jay
    Replies:
    8
    Views:
    6,582
    livshitz
    Jun 12, 2011
  2. Herman Geldenhuys

    Tkinter main window needs to disappear

    Herman Geldenhuys, Mar 5, 2004, in forum: Python
    Replies:
    1
    Views:
    298
    Peter Otten
    Mar 5, 2004
  3. Eric McRae
    Replies:
    1
    Views:
    326
    Jason Harper
    Oct 25, 2004
  4. Replies:
    1
    Views:
    601
    Steve Holden
    Apr 30, 2005
  5. Robert Oschler
    Replies:
    1
    Views:
    392
Loading...

Share This Page