Is there any external library implementing validators for specific controls/data types?
What should a validator do?
Is it a good idea for the validator to return the expected data type?
For example, FloatValidator for wx.TextCtrl after calling .Validate() sets the .value variable of the validator to the float data type?
For example:
ctrl = wx.TextCtrl(..., validator=FloatValidator())
ctrl.Validator.value = 2.0 # assign value
assert ctrl.TransferDataToWindow() # pass the converted value to the control
assert ctrl.Value == "2.0"
ctrl.Value = "3.0" # set new value
if ctrl.Validate():
v = ctrl.Validator.value
assert isinstance(v, float)
assert v == 3.0
It seems that’s exactly what I had in mind.
I’m just wondering if the correct approach is to assign a value to the control and get the user-entered values using a validator.
That is certainly an interesting solution. I don’t remember seeing anything similar before.
My use of validators is fairly simple and mostly based on the examples in the wxPython Demo and the “wxPython In Action” book. In these examples the TransferToWindow() and TransferFromWindow() methods simply return True and the application itself gets the value by calling the TextCtrl.GetValue() and converting the value at that point.
I can see the advantage of your technique in that the validator class can be reused in different applications without repeating the conversion code.
well, for me the advantage of a validator is in the event OnChar in order to distinguish Text and Integer (a commercial GUI also does it without coding)
for the rest I think you make out of a two or three liner a lot of may be confusing coding (especially the difference between Frame and Dialog)
BTW to turn a 1 quietly into a 1.0 is for a lot of people a problem because a 1 means I don’t no more and a 1.0 means the first digit is 0
for technically minded people 1 and 1.0 are not equal (in Python they are)
here is a reusable alpha/digit checker (no-frills but just plug in)
import string
import wx
class DigitAlphaVal(wx.Validator):
def __init__(self, flag=None):
# flag should be 'a' for alpha or 'd' for digit
super().__init__()
self.flag = flag.upper()
if self.flag in ('A', 'D'):
self.Bind(wx.EVT_CHAR, self.OnChar)
def Clone(self):
return self
def OnChar(self, event):
key = event.GetKeyCode()
if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
event.Skip()
return
if self.flag == 'A' and chr(key) in string.ascii_letters:
event.Skip()
return
if self.flag == 'D' and chr(key) in string.digits:
print(string.digits)
event.Skip()
return
if not wx.Validator.IsSilent():
wx.Bell()
# Returning without calling even.Skip eats the event before it
# gets to the text control
return
import string
import wx
class DigitAlphaVal(wx.Validator):
def __init__(self, flag=None):
# flag should be 'a' for alpha or 'd' for digit
super().__init__()
self.flag = flag.upper()
if self.flag in ('A', 'D'):
self.Bind(wx.EVT_CHAR, self.OnChar)
self.textCtrl = None
def Clone(self):
return self
def OnChar(self, event):
if not self.textCtrl:
self.textCtrl = self.GetWindow()
self.textCtrl.Bind(wx.EVT_TEXT, self.evt_text)
self.ctext = self.textCtrl.GetValue()
key = event.GetKeyCode()
if mod := event.GetModifiers():
event.Skip()
if mod != 2:
self.textCtrl.Clear()
else:
if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
event.Skip()
return
if self.flag == 'A' and chr(key) in string.ascii_letters:
event.Skip()
return
if self.flag == 'D' and chr(key) in string.digits:
event.Skip()
return
if not self.IsSilent():
wx.Bell()
# Returning without calling even.Skip eats the event before it
# gets to the text control
return
def evt_text(self, evt):
txt = evt.GetString()
if (self.flag == 'A' and txt.isalpha() or
self.flag == 'D' and txt.isdecimal()):
self.ctext = self.textCtrl.GetValue()
else:
if not self.textCtrl.GetLastPosition():
self.ctext = ''
self.textCtrl.ChangeValue(self.ctext)
if not self.IsSilent():
wx.Bell()
that’s not a task for a validator because ‘validation’ depends on some end event, i.e. it is normal text input checking (maybe triggered by EVT_TEXT_ENTER or some button)