Jim Robinson
Jim Robinson

Reputation: 309

tk.Entry validate command doesn't restore previous value when False returned

I have carefully reviewed answers to Interactively validating Entry widget content in tkinter, but my script fails to restore previous value if the validate command returns False. I captured %P and %s and print them out...They both show the same value.

import tkinter as tk

class Controller :
    def __init__(self) :
        i=10
        j=20
        # list comprehension
        self.entry_widgets = [[None for col in range(j)] for row in range(i)]
        #print(self.entry_widgets)

        self.values = [["string"+str(row) + str(col) for col in range(10)] for row in range(20)]
        #print(self.values)
class EnterBox(tk.Entry):

    def __init__(self,*args,**kwargs):
        #print (args)
        self._modified = False
        self._save = 0
        self._raise = 1
        self._lower = 2


        frame, i,j, *newargs = args
        self._content = tk.StringVar()

   #        tk.Entry.__init__(self,frame,*newargs,
   #                          validate = 'focusout', 
   #                          validatecommand = vcmd,
   #                          **kwargs)
        tk.Entry.__init__(self,frame,*newargs,**kwargs)

        vcmd = (self.register(self._revert), '%P', '%s')
        ct.entry_widgets[i][j] = self
        self.config(textvariable=self._content)
        self.config(validate = "focusout")
        self.config(validatecommand = vcmd )
        x=(ct.values[i][j])
        self.insert(0,x)
       #self._content.set(x)
        self.bind("<Return>",lambda  event, x=self._save : self._action(event,x) )
        self.bind("<Button-2>",lambda event, x=self._save : self._action(event,x) )
        self.bind("<FocusIn>", lambda event, x=self._raise : self._action(event,x))
        self.bind("<FocusOut>", lambda event, x=self._lower : self._action(event,x))
        self.bind('<Button-3>', lambda event, x=self._lower : self._action(event,x))

        self.grid(column=i+1,row=j+2)

def _revert(self,P,s):
    print ("Hi There")
    print(P)
    print(s)
    return False
def _action(self,event,action):
    print(str(action)+' ' + str(event))
    if action == self._save :
        ct.values[i][j] = self._content.get()
        self.config(bg='lightskyblue2')
        self._modified = True
    elif action == self._raise :
        self.config(bg = 'light pink')
    elif action == self._lower :
        self.config(bg = 'gray80')
        self._modified = False
    else :
        print('action value is bad action =>' + str(action))
if "__main__" == __name__ :
    root = tk.Tk()
    frame = tk.Frame()
    i=j=0

    ct = Controller()
    root.grid()
    frame.grid()
    check = EnterBox(frame,i,j,width = 24)
    check2 = EnterBox(frame,i+1,j,width = 24)
    root.mainloop()

I have tried removing all other bindings, to no avail. Interestingly, but a separate issue, If I use StringVar. set instead of self.insert, (see commented out line) the validate command runs once, and never again despite several focus changes. Using Python 3.8

Upvotes: 0

Views: 496

Answers (1)

Bryan Oakley
Bryan Oakley

Reputation: 386342

The validation isn't designed to restore anything if the validation happens on focusout. The validation can only prevent characters from being added at the time they are added. You will have to add code to restore the previous value.

Upvotes: 2

Related Questions