[Tutor] Tkinter

Michael Lange klappnase at freenet.de
Sat Mar 6 21:47:58 EST 2004


On Sat, 6 Mar 2004 17:25:37 -0800 (PST)
Marilyn Davis <marilyn at deliberate.com> wrote:

> 
> > Tk() is the application's main (or root) window; any Tkinter app
> > needs a Tk() window as parent for all the other widgets.
> >
> > That's why you have to call the mainloop() for your Tk() window to
> > keep the whole thing alive.
> >
> > The toplevel widget (called with the Toplevel() command) is a window
> > that looks just like the Tk() window, but is in fact a child of the
> > mainwindow. You don't need to call a mainloop() on Toplevel() windows.
> 
> And you don't call mainloop on any "slaves"?

Right - never.

> 
> Is 'slaves' the right word?  I see 'master' and I see 'children'.
> Maybe 'slaves' is politically incorrect -- but technically correct?  I
> don't like 'children' because it can be confused with inheritance
> hierarchies.

Most people say "parent" and "children" I think; for political correctness reasons
maybe we should use "president" and "citizens" ;-)

> > About the example with MyClass(Frame) I can just guess; maybe the
> > code looked like this:
> > 
> > root = Tk()
> > o = MyClass(root)#Frame that contains some other widgets
> > o.pack()
> 
> Nope, surprisingly, the examples from the Deitel book look like:
> 
> # Fig. 11.5: fig11_05.py
> # Canvas paint program.
> 
> from Tkinter import *
> 
> class PaintBox( Frame ):
>    """Demonstrate drawing on a Canvas"""
>    
>    def __init__( self, title='A simple paint program'):
>       """Create Canvas and bind paint method to mouse dragging"""
>       
>       Frame.__init__( self )
>       self.pack( expand = YES, fill = BOTH )
>       self.master.title( title)
>       self.master.geometry( "300x150" )
> 
>       self.message = Label( self, text = "Drag the mouse to draw" )
>       self.message.pack( side = BOTTOM )
>       
>       # create Canvas component
>       self.myCanvas = Canvas( self )
>       self.myCanvas.pack( expand = YES, fill = BOTH )
> 
>       # bind mouse dragging event to Canvas
>       self.myCanvas.bind( "<B1-Motion>", self.paint )
> 
>    def paint( self, event ):
>       """Create an oval of radius 4 around the mouse position"""
>       
>       x1, y1 = ( event.x - 4 ), ( event.y - 4 )
>       x2, y2 = ( event.x + 4 ), ( event.y + 4 )
>       self.myCanvas.create_oval( x1, y1, x2, y2, fill = "black" )
>    
> def main():
>    PaintBox().mainloop()
> 
> if __name__ == "__main__":
>    main()
> 
> --------
> 
> >  Now when you destroy the MyClass instance an empty window should be
> > left (the Tk() was not destroyed) which might look like a window
> > with a frame inside (an empty gray rectangle).
> 
> Yes.  This happened.  But when I called myclass.master.destroy(), it
> all went away.  So I'm thinking that if you instantiate Frame without
> a master, it automatically makes a Tk object for you to be your
> master?  Or a Toplevel object for you?  Probably Tk?
> 

Seems like we find the magic for this in Tkinter.py, line 1717 ff.(Python2.2.1):

class BaseWidget(Misc):
    """Internal class."""
    def _setup(self, master, cnf):
        """Internal function. Sets up information about children."""
        if _support_default_root:
            global _default_root
            if not master:
                if not _default_root:
                    _default_root = Tk()
                master = _default_root


> (It's cool, the slave generates the master.  Maybe that's politically
> correct.)

I guess somehow they always do so. However, viewed from this aspect I think I should
better drop the "president" / "citizen" suggestion. How about "employer" and "employees" ?

> 
> I don't think I ever got it to call my __del__ method though.  I wonder
> what is the relationship between destroy() and __del__().  Maybe I have
> to look at the source code some time.
> 

I did so, Tkinter.py line 1760 ff. shows BaseWidget.destroy():

def destroy(self):
        """Destroy this and all descendants widgets."""
        for c in self.children.values(): c.destroy()
        if self.master.children.has_key(self._name):
            del self.master.children[self._name]
        self.tk.call('destroy', self._w)
        Misc.destroy(self)

Complicated! Base.Widget.destroy() calls Misc.destroy() (Tkinter.py line 282 ff.):

    def destroy(self):
        """Internal function.

        Delete all Tcl commands created for
        this widget in the Tcl interpreter."""
        if self._tclCommands is not None:
            for name in self._tclCommands:
                #print '- Tkinter: deleted command', name
                self.tk.deletecommand(name)
            self._tclCommands = None

However, most people seem to prefer the quit() method to close Tkinter apps anyway, destroy() only to
get rid of some "employees" (mostly Toplevels I guess)
Now that I have already Tkinter.py opened, I see this is a method of the Misc class, too:

    def quit(self):
        """Quit the Tcl interpreter. All widgets will be destroyed."""
        self.tk.quit()

I am not that kind of expert, but I think I read something about the reasons for quit() to be the preferred method,
unfortunately I must admit I forgot about the details.

I hope this helped a little more

Michael





More information about the Tutor mailing list