A validator object is a subclass of wx.Validator. The parent class is abstract, and isn't used directly. Although there are a couple of predefined validator classes in the C++ wxWidget set, in wxPython, you will need to define your own validator classes. As we've seen in other cases, your Python classes need to inherit from a Python-specific subclass, wx.PyValidator, to be able to override all the parent methods. A custom validator subclass must also override the method Clone(), which should return an identical copy of the validator.
A validator is attached to a specific widget in your system. That can be accomplished in one of two ways. First, if the widget allows it, the validator can be passed as an argument to the widget constructor. If the widget does not have a validator argument to its constructor, you can still attach a validator by creating a validator instance and calling the widget's SetValidator(validator) method.
To validate the data in the control, start by overriding the method Vali-date(parent) in your validator subclass. The parent argument is the parent window of the validator's widget, either the dialog or a panel. Use this to get the data from other widgets in the dialog if that's important, or you can ignore the argument altogether. You can use self.GetWindow() to get a reference to the widget being validated. The return value of your Validate(parent) method is a Boolean. A True value indicates to the rest of the system that the data in the validator's widget is valid. A False value indicates a problem. You are allowed to use wx.MessageBox() to display an alert from the Validate() method, but you shouldn't do anything else that could raise events in the wxPython application.
The return value of the Validate() method is important. It comes into play when you attempt to close a dialog using the OK button, (the button with an ID of wx.ID_OK). As part of the processing of the OK click, wxPython calls the Vali-date() function of any widget the dialog contains that has a validator. If any of those methods return False, the dialog will not close. Listing 9.13 displays a sample dialog with a validator that checks to see that all text controls have data.
Listing 9.13 A validator checking that all text controls have data import wx about_txt = \
The validator used in this example will ensure that the text controls are not empty when you press the Ok button, and will not let you leave if any of the Validations fail."""
class NotEmptyValidator(wx.PyValidator): <1— Creating the validator subclass def __init__(self):
Note that every validator must implement the Clone() method.
def Validate(self, win): b Using the validator method textCtrl = self.GetWindow() text = textCtrl.GetValue()
wx.MessageBox("This field must contain some text!", "Error") textCtrl.SetBackgroundColour("pink") textCtrl.SetFocus() textCtrl.Refresh() return False else:
wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) textCtrl.Refresh() return True def TransferToWindow(self): return True def TransferFromWindow(self): return True class MyDialog(wx.Dialog):
wx.Dialog._init_(self, None, -1, "Validators: validating")
# Create the text controls about = wx.StaticText(self, -1, about_txt)
name_l = wx.StaticText(self, -1, "Name:")
email_l = wx.StaticText(self, -1, "Email:")
phone_l = wx.StaticText(self, -1, "Phone:")
name_t = wx.TextCtrl(self, validator=NotEmptyValidator()) email_t = wx.TextCtrl(self, validator=NotEmptyValidator()) phone_t = wx.TextCtrl(self, validator=NotEmptyValidator())
Using the validator (
# Use standard button IDs okay = wx.Button(self, wx.ID_OK) okay.SetDefault()
cancel = wx.Button(self, wx.ID_CANCEL)
# Layout with sizers sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(about, 0, wx.ALL, 5)
sizer.Add(wx.StaticLine(self), 0, wx.EXPAND|wx.ALL, 5)
fgs = wx.FlexGridSizer(3, 2, 5, 5) fgs.Add(name_l, 0, wx.ALIGN_RIGHT) fgs.Add(name_t, 0, wx.EXPAND) fgs.Add(email_l, 0, wx.ALIGN_RIGHT) fgs.Add(email_t, 0, wx.EXPAND)
fgs.Add(phone_l, 0, wx.ALIGN_RIGHT) fgs.Add(phone_t, 0, wx.EXPAND) fgs.AddGrowableCol(1)
btns = wx.StdDialogButtonSizer() btns.AddButton(okay) btns.AddButton(cancel) btns.Realize()
app = wx.PySimpleApp()
O This method tests that the underlying control has some data. If it does not, the background color of the widget is changed to pink.
C In these lines, a new validator it attached to each text field in the dialog.
Figure 9.13 displays the dialog after attempting to close it with a blank field.
The code that explicitly tells the dialog to check the validators is not in the listing—it is a part of the wxPython event system. Another difference between dialogs and frames is that dialogs have the validator behavior built-in and frames do not. If you would like to use validators for validating controls not located in a dialog, call the parent window's Validate() method. If the wx.ws_ex_validate_recursively extra style is set for the window, Validate() of all the child windows is also called. If any of the validations fail, Validate returns False. Next, we'll discuss how to use validators to transfer data.
Was this article helpful?