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