Home > Mobile >  Validatecommand is called when I edit the entry programmatically
Validatecommand is called when I edit the entry programmatically

Time:05-15

I am trying to create an entry with a very special validation. For that, I'm playing dirty with validatecommand. However, I got a problem:

When something in the entry is deleted, I can't tell if it was done with the delete or backspace key (and tutorial pages like this: https://www.pythontutorial.net/tkinter/tkinter-validation/ no substitution is indicated provide that information).

So, I decided to add a bind. The function that I link returns "break" and must take care of removing a character and inserting a space in its place.

The problem, as the title says, is that validatecommand even validates entry edits made with the insert and delete methods.

To avoid this I considered disabling validation (which always returns True) while I make the corresponding edits. But this could cause other entries not to be validated.

Is there a way to skip that validation when programmatically editing an entry?

I leave you this code so that you have some basis to help me:

from functools import partial

class ChrFormat:
    def __init__(self):
        self.charvalidators = []

    def register_in(self, widget):
        widget.config(validate="key", validatecommand=(widget.register(partial(self, widget)), "%d", "%i", "%P", "%s", "%S"))

    def add(self, obj):
        self.charvalidators.append(obj)

    def __call__(self, widget, accion, index, new_text, old_text, char):
        accion = int(accion)
        index = int(index)
        
        if(len(char) == 1):
            if(accion == 1):
                if(index < self.width):
                    for validator in self.charvalidators[index:]:
                        if(not isinstance(validator, str)):
                            break
                        index  = 1
                    else:
                        return False

                    if(validator(char)):
                        widget.delete(index)
                        widget.insert(index, char)
                        widget.icursor(index   1)

        return (accion != 1)

    def apply(self):
        self.width = len(self.charvalidators)
        self.null = "".join((part if(isinstance(part, str)) else " ") for part in self.charvalidators)

fecha = ChrFormat()
fecha.add(str.isdecimal)
fecha.add(str.isdecimal)
fecha.add("-")
fecha.add(str.isdecimal)
fecha.add(str.isdecimal)
fecha.add("-")
fecha.add(str.isdecimal)
fecha.add(str.isdecimal)
fecha.add(str.isdecimal)
fecha.add(str.isdecimal)
fecha.apply()

from tkinter import ttk
import tkinter as tk

root = tk.Tk()

sv = tk.StringVar()

entrada = ttk.Entry(textvariable=sv)
entrada.pack()

fecha.register_in(entrada)

sv.set(fecha.null)

I think I didn't explain myself well, sorry. What I'm looking for is that when the user presses backspace, it deletes a number and puts a space in its place. And something similar with delete. But I need to know which side of the cursor to put that space on.

Obviously, natural validation is the right thing for this, maybe do the validation through binds.

For those who know a bit about Clipper programming languaje, I want to mimic what happens when a picture is placed, such as '@r 999.999'. I would post a video, but I'm not in a good time to record and I didn't find any videos to prove it.

CodePudding user response:

Is there a way to skip that validation when programmatically editing an entry?

The simplest solution is to set the validate option to "none" before making the edits. You then can turn the validation back on via after_idle as documented in the official tk documentation

widget.configure(validate="none")
widget.delete(index)
widget.insert(index, char)
widget.icursor(index   1)
widget.after_idle(lambda: widget.configure(validate="key"))
  • Related