[Edu-sig] Python Help - Thanks [callbacks]

Danny Yoo dyoo@hkn.eecs.berkeley.edu
Tue, 20 May 2003 09:25:14 -0700 (PDT)


On Tue, 20 May 2003, Randy Latimer wrote:

> Here's the problem:
>     She's defining a a DrawCircle function in class easel (the drawing
>         canvas)
>     The button for "Circle" is defined in the "panel" - tool bar.
>     She's trying to call the DrawCircle function when she left clicks
>       on the Circle button.
>     But nothing happens now when the Circel button is pressed.

Hi Randy,


A valuable part of programming is knowing what to investigate when a
program fails.  Since nothing's happening when the circle button is
pressed, we may want to look at the particular code that binds the button
to the DrawCircle function: there might be something there that we need to
look at.


The binding code is defined in the MakeGUI() method of the panel:

###
    def MakeGUI(self,MyEasel,MyCanvas):
        Circle = Button (self,text = "Circle")
        Circle.pack(side = TOP,fill = X, anchor = N)
        Circle.bind('<Button-1>', self.circle(self, MyEasel, MyCanvas))
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
###


Ah!  This bit of code looks suspicious.  There are a few things wacky with
it The expression,

    self.circle(self, MyEasel, MyCanvas)

calls the method circle() --- but isn't it a bit premature to call it now,
during the MakeGUI initialization?

Also, 'self' is already an implicit first argument in a method call, so
the first argument to this call looks redundant.  Looking at the
self.circle definition, I'm assuming that you meant to send over the event
object?

Side note: it seems a little silly to pass MyEasel and MyCanvas around
everywhere; wouldn't it be better to make them attributes of our object?



Sorry, I'm getting backtracked.  *grin* The problem appears to be a
confusion on how callbacks work.  The code desires to bind <Button-1> to a
function that, when called, will itself call self.circle():

###
    def bringUpCircle(event):
        self.circle(MyEasel, MyCanvas)
###


And since it's perfectly ok to define internal functions in a method, we
can fix the binding bug by doing something like this:

###
    def MakeGUI(self,MyEasel,MyCanvas):
        Circle = Button (self,text = "Circle")
        Circle.pack(side = TOP,fill = X, anchor = N)

        def bringUpCircle(event):
            self.circle(event, MyEasel, MyCanvas)

        Circle.bind('<Button-1>', bringUpCircle)
###

For more information, see:

http://www.pythonware.com/library/tkinter/introduction/events-and-bindings.htm


Good luck to you!