[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