[Tutor] Question on tkinter event binding

Albert-Jan Roskam fomcl at yahoo.com
Sat Dec 4 21:00:21 CET 2010


Hi Steven,

Awesome, I've got it working now!  Here's the code:  
http://pastebin.com/BQhW8piD (I also pasted it below this message).
I tried your approach before but I abandoned it because I made a mistake in 
lines 16 (pass None for event) and 22 (I didn't use the parameters of the outer 
function as the arguments of the inner function. Thanks a lot for putting me 
back on the right track!! It's really working cool now and I was able to remove 
some unnecessary code (and I added some bells and whistles ;-))

Cheers!!
Albert-Jan

import Tkinter, time, sys

# To be used in conjunction with the AutocompleteEntry class:
# http://tkinter.unpythonic.net/wiki/AutocompleteEntry

def createWidgets(veldnamen, termenlijst):
    root=Tk()
    for veldnaam in veldnamen:
        labelWidget=Tkinter.Label(root, text=veldnaam, takefocus=False)
        labelWidget.grid()
        # tcl names must start with a lowercase letter
        tclName = veldnaam[0].lower() + veldnaam[1:]
        entryWidget=Tkinter.Entry(root, name=tclName, highlightcolor="yellow")
        entryWidget.grid()
        makeDeletionHandler(event=None,
                            widget=entryWidget,
                            root=root,
                            termenlijst=termenlijst)

def makeDeletionHandler(event, widget, root, termenlijst):
    def handleDeletion(event, widget=widget, root=root, 
termenlijst=termenlijst):
        vensternaam = str(widget)[1:].capitalize()
        if vensternaam.startswith("*"):
            vensternaam = "*" + vensternaam[1:].capitalize()
        vensterinhoud = widget.get().strip()
        print "Name: %s -- Contents: %s" % (vensternaam, vensterinhoud)
        try:
            termenlijst[vensternaam].remove(vensterinhoud)
            widget.delete(0, END)
            widget.configure(bg = "green")
            #print termenlijst
            print "Deleted term '%s'" % vensterinhoud
        except KeyError:
            print "No such term '%s'" % vensterinhoud
            pass
        finally:
            delay = 0.5
            if sys.platform.lower().startswith("win"):
                delay = delay * 1000
            time.sleep(delay) # Windows: specify in ms!)
            widget.configure(bg = "white")
    widget.bind("<Shift-Delete>", handleDeletion)
    return handleDeletion

createWidgets(veldnamen = ["Naam", "*Postcode", "Adres", "*Organization name"],
              termenlijst = {"Naam": set(["Bill Gates", "Elvis Presley"]),
                             "*Postcode": set(["2600AA", "8000BB"]),
                             "Adres": set(["Street", "Avenue"]),
                             "*Organization name": set(["CWI", "MIT"])})




~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
All right, but apart from the sanitation, the medicine, education, wine, public 
order, irrigation, roads, a fresh water system, and public health, what have the 
Romans ever done for us?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~




________________________________
From: Steven D'Aprano <steve at pearwood.info>
To: Python Mailing List <tutor at python.org>
Sent: Sat, December 4, 2010 3:49:26 PM
Subject: Re: [Tutor] Question on tkinter event binding

Albert-Jan Roskam wrote:

> Meanwhile, I tinkered a bit more with the code. I used exec() to isolate the 
>event handler function. It works and it's better, but I think it could be still 
>better. I'm not so fond of eval() and exec().

They have their uses, but yes, it's best to avoid them unless you need them. 
Let's see if we can avoid them :)


> from Tkinter import *
> 
> def createWidgets(veldnamen):
>     root=Tk()
>     termenlijst = {"Naam": set(["Bill Gates", "Elvis Presley"]),
>                    "*Postcode": set(["2600AA", "8000BB"]),
>                    "Adres": set(["Street", "Avenue"])}
>     handleDeletions = {}
>     for veldnaam in veldnamen:
>         labelWidget=Label(root, text=veldnaam,  takefocus=False)
>         labelWidget.grid()
>         # tcl names must start with a lowercase letter
>         tclName = veldnaam[0].lower() + veldnaam[1:]
>         content = StringVar()
>         entryWidget=Entry(root, name=tclName, textvariable=content)
>         entryWidget.grid()
> 
>         exec(doHandleDeletion())
>         handleDeletions[entryWidget] = handleDeletion

The classic solution for callbacks is to use lambda, but of course lambda is 
limited to a single expression and won't do the job here. So what you need is a 
factory function that returns a new function:

        handleDeletions[entryWidget] = make_deletion_handler()


and the factory itself is defined something like  this:


def make_deletion_handler():
    # Create a function.
    def handleDeletion(event, widget=entryWidget, root=root,
                       termenlijst=termenlijst, content=content):
        actieveVenster = root.focus_get()
        actieveVensternaam = str(actieveVenster)[1:].capitalize()
        if actieveVensternaam.startswith("*"):
            actieveVensternaam = "*"+actieveVensternaam[1:].capitalize()
            vensterinhoud = content.get().strip()
            print "Name: %s -- Contents: %s" \
                  % (actieveVensternaam, vensterinhoud)
            try:
                 termenlijst[actieveVensternaam].remove(vensterinhoud)
                actieveVenster.delete(0, END)
                print "Deleted term '%s'" % vensterinhoud
            except KeyError:
                print "No such term '%s'" % vensterinhoud
    # And return it.
    return handleDeletion


If you move the factory outside of your createWidgets function, you will need to 
explicitly pass arguments entryWidget, content, etc. to the factory. Otherwise 
you can nest the factory inside createWidgets, at it will pick the variables up 
automatically.


Hope this helps,



-- Steven
_______________________________________________
Tutor maillist  -  Tutor at python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor



      
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tutor/attachments/20101204/e21f5535/attachment.html>


More information about the Tutor mailing list