views:

875

answers:

3

Hey,

I'm writing some code in python and I'm having trouble when trying to retrieve content of an Entry widget. The thing is: I want to limit the characters that can be typed, so I'm trying to clear the Entry widget when I reach the specific number of characters (2 in this case), but it looks like I always miss the last typed character. I added the lost character in a print to show.

Here's the sample code:

from Tkinter import *
class sampleFrame:
    def __init__(self, master):
        self.__frame = Frame(master)
        self.__frame.pack()
    def get_frame(self):
        return self.__frame


class sampleClass:
    def __init__(self, master):
        self.__aLabel = Label(master,text="aLabel", width=10)
        self.__aLabel.pack(side=LEFT)
        self.__aEntry = Entry (master, width=2)
        self.__aEntry.bind('<Key>', lambda event: self.callback(event, self.__aEntry))
        self.__aEntry.pack(side=LEFT)

    def callback(self, event, widgetName):
        self.__value = widgetName.get()+event.char
        print self.__value
        if len(self.__value)>2:
            widgetName.delete(2,4)





root = Tk()
aSampleFrame = sampleFrame(root)
aSampleClass = sampleClass(aSampleFrame.get_frame())
root.mainloop()

Any help will be much appreciated!

Thanks in advance

+3  A: 

At first, after you do the deletion, the event goes on with its normal processing, i.e. the character gets inserted. You need to signal to Tkinter that the event should be ignored.

So in your code above, add the marked line:

if len(self.__value) > 2:
    widgetName.delete(2,4)
    return "break" # add this line

On the other hand, why do you go through the lambda? An event has a .widget attribute which you can use. So you can change your code into:

    self.__aEntry.bind('<Key>', self.callback) # ※ here!
    self.__aEntry.pack(side=LEFT)

def callback(self, event):
    self.__value = event.widget.get()+event.char # ※ here!
    print self.__value
    if len(self.__value)>2:
        event.widget.delete(2,4) # ※ here!
        return "break"

All the changed lines are marked with "here!"

ΤΖΩΤΖΙΟΥ
A: 

ΤΖΩΤΖΙΟΥ,

Thank you a lot! I didn't realize that i needed the "break". That is perfect! Thanks! Also, thanks a lot for the tip about the event.widget. I was using the wrong syntax and ended up with the lambda to overcome that!

Thanks a lot! Perfect answer, issue closed!

Glad I could help; please note that you should write the text of your answer as a comment to my answer, and then you should delete your answer, because it's not an answer to your question.
ΤΖΩΤΖΙΟΥ
+1  A: 

To be a bit more specific, Tk widgets have what are called "bindtags". When an event is processed, each bindtag on the widget is considered in order to see if it has a binding. A widget by default will have as its bindtags the widget, the widget class, the root widget, and "all". Thus, bindings to the widget will occur before the default bindings. Once your binding has been processed you can prevent any further bindtags from being considered by returning a "break".

The ramifications are this: if you make a binding on the widget, the class, root window and "all" bindings may fire as well. In addition, any binding you attach to the widget fires before the class binding which is where the default behavior (eg: the insertion of a character) happens. It is important to be aware of that in situations where you may want to handle the event after the default behavior rather than before.

Bryan Oakley