[Tutor] Question on tkinter event binding

Albert-Jan Roskam fomcl at yahoo.com
Fri Dec 3 21:18:40 CET 2010


Aaahhh, got it! Peace! I did two things wrong: (1) I didn't use a tcl 
StringVar() to get the entry widget contents (2) I didn't consistently close the 
menus generated by previous attempts to run the program, which led to 
inconsistent results.

I'll paste the working code below. It's partially in Dutch, but hey, so is Guido 
van Rossem. ;-)

Even so, I'd be happy to hear suggestions for improvement or simplification. I'd 
love to chop the code up into smaller, more comprehensible bits.

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()

        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
                pass
        handleDeletions[entryWidget] = handleDeletion

    for entryWidget, handleDeletion in handleDeletions.iteritems():
        entryWidget.bind("<Shift-Delete>", handleDeletion)

createWidgets(["Naam", "*Postcode", "Adres"])


 

 Cheers!!
Albert-Jan


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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: Albert-Jan Roskam <fomcl at yahoo.com>
To: Python Mailing List <tutor at python.org>
Sent: Fri, December 3, 2010 11:19:02 AM
Subject: [Tutor] Question on tkinter event binding


Hi,

I'm trying to make a small improvement on a data entry program and it is 
literally giving me a headache. I would appreciate your help or suggestions. 


The actual program uses Autocomplete entry widgets [1], which is a subclass of 
the Tkinter Entry widget. The sample code below uses a simple Entry widget, for 
the sake of simplicity. The autocompletions are recorded in a dictionary of the 
form {entry name: set(<entries>)}. The problem is that entries with typos cannot 
be deleted, so wrong autocomplete suggestions ("Bbbilly Gates") are given until 
the end of time. My solution: I want to bind each entry widget to the Delete 
key, which makes it possible to remove the typo-entry from the set of entries. I 
am using an ' expanded event handler' [2] to do the event  binding.

The sample code below creates two entry widgets. The problem is that the entry 
contents is not retrieved correctly. If I fill the 2nd entry with some text, 
then hit 'Del' , it shows the content of the *first* entry. Also, I would like 
to isolate the event handler into its own function, not as a function within a 
function, but I'm not quite sure how.

[1] http://tkinter.unpythonic.net/wiki/AutocompleteEntry
[2] http://www.daniweb.com/code/snippet306072.html

from Tkinter import *

def createWidgets(veldnamen):
    root=Tk()
    termenlijst = {"Naam": set(["Bill Gates", "Elvis Presley"]), "*Postcode": 
set(["2600AA", "8000NN"])}
    handleDels = {}
    for veldnaam  in veldnamen:
        # tcl names must start with lowercase letter
        entryWidget=Entry(root, name=veldnaam[0].lower() + veldnaam[1:])
        entryWidget.grid()
        def handleDel(event, widget=entryWidget, root=root, 
termenlijst=termenlijst):
            vensternaam = str(root.focus_get())[1:].capitalize() # ... and back 
to uppercase
            if vensternaam.startswith("*"):    # mandatory fields start with '*' 
in my program.
                vensternaam = "*" + vensternaam[1:].capitalize()
            vensterinhoud =  entryWidget.get()
            print "Naam", vensternaam       # entry name
            print "Inhoud", vensterinhoud   # entry contents
            try:
                termenlijst[vensternaam].remove(vensterinhoud)  # here's where 
the typo is removed
            except KeyError:
                pass # user tries to delete a term that doesn't exist in the 
termenlijst.
        handleDels[entryWidget] = handleDel
    # do all the bindings (is this where it goes  wrong??)
    for entryWidget, handleDel in handleDels.iteritems():
        entryWidget.bind("<Delete>", handleDel)
    print handleDels
    print termenlijst

createWidgets(["Naam", "*Postcode"])

 
Thanks again for having a look at this.

Cheers!!
Albert-Jan


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


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


More information about the Tutor mailing list