wx.TextCtrl and wx.Validator

13,648

Solution 1

This is a feature of wxWidgets, and is not implemented in wxPython.

http://www.wxpython.org/docs/api/wx.TextValidator-class.html - not found

while:

http://docs.wxwidgets.org/trunk/classwx_text_validator.html http://docs.wxwidgets.org/stable/wx_wxtextvalidator.html

There is a demo of the Validators in the wxPython demo:

import wx

class TextObjectValidator(wx.PyValidator):
     """ This validator is used to ensure that the user has entered something
         into the text object editor dialog's text field.
     """
     def __init__(self):
         """ Standard constructor.
         """
         wx.PyValidator.__init__(self)



     def Clone(self):
         """ Standard cloner.

             Note that every validator must implement the Clone() method.
         """
         return TextObjectValidator()


     def Validate(self, win):
         """ Validate the contents of the given text control.
         """
         textCtrl = self.GetWindow()
         text = textCtrl.GetValue()

         if len(text) == 0:
             wx.MessageBox("A text object must contain some text!", "Error")
             textCtrl.SetBackgroundColour("pink")
             textCtrl.SetFocus()
             textCtrl.Refresh()
             return False
         else:
             textCtrl.SetBackgroundColour(
                 wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
             textCtrl.Refresh()
             return True


     def TransferToWindow(self):
         """ Transfer data from validator to window.

             The default implementation returns False, indicating that an error
             occurred.  We simply return True, as we don't do any data transfer.
         """
         return True # Prevent wxDialog from complaining.


     def TransferFromWindow(self):
         """ Transfer data from window to validator.

             The default implementation returns False, indicating that an error
             occurred.  We simply return True, as we don't do any data transfer.
         """
         return True # Prevent wxDialog from complaining.

#----------------------------------------------------------------------

class TestValidateDialog(wx.Dialog):
    def __init__(self, parent):
        wx.Dialog.__init__(self, parent, -1, "Validated Dialog")

        self.SetAutoLayout(True)
        VSPACE = 10

        fgs = wx.FlexGridSizer(0, 2)

        fgs.Add((1,1));
        fgs.Add(wx.StaticText(self, -1,
                             "These controls must have text entered into them.  Each\n"
                             "one has a validator that is checked when the Okay\n"
                             "button is clicked."))

        fgs.Add((1,VSPACE)); fgs.Add((1,VSPACE))

        label = wx.StaticText(self, -1, "First: ")
        fgs.Add(label, 0, wx.ALIGN_RIGHT|wx.CENTER)

        fgs.Add(wx.TextCtrl(self, -1, "", validator = TextObjectValidator()))

        fgs.Add((1,VSPACE)); fgs.Add((1,VSPACE))

        label = wx.StaticText(self, -1, "Second: ")
        fgs.Add(label, 0, wx.ALIGN_RIGHT|wx.CENTER)
        fgs.Add(wx.TextCtrl(self, -1, "", validator = TextObjectValidator()))


        buttons = wx.StdDialogButtonSizer() #wx.BoxSizer(wx.HORIZONTAL)
        b = wx.Button(self, wx.ID_OK, "OK")
        b.SetDefault()
        buttons.AddButton(b)
        buttons.AddButton(wx.Button(self, wx.ID_CANCEL, "Cancel"))
        buttons.Realize()

        border = wx.BoxSizer(wx.VERTICAL)
        border.Add(fgs, 1, wx.GROW|wx.ALL, 25)
        border.Add(buttons)
        self.SetSizer(border)
        border.Fit(self)
        self.Layout()



app = wx.App(redirect=False)
f = wx.Frame(parent=None)
f.Show()
dlg = TestValidateDialog(f)
dlg.ShowModal()
dlg.Destroy()

app.MainLoop()

Solution 2

There are lots of ways to do this. The wxPython demo actually shows how to allow only digits or only alpha. Here's an example based on that:

import wx
import string

########################################################################
class CharValidator(wx.PyValidator):
    ''' Validates data as it is entered into the text controls. '''

    #----------------------------------------------------------------------
    def __init__(self, flag):
        wx.PyValidator.__init__(self)
        self.flag = flag
        self.Bind(wx.EVT_CHAR, self.OnChar)

    #----------------------------------------------------------------------
    def Clone(self):
        '''Required Validator method'''
        return CharValidator(self.flag)

    #----------------------------------------------------------------------
    def Validate(self, win):
        return True

    #----------------------------------------------------------------------
    def TransferToWindow(self):
        return True

    #----------------------------------------------------------------------
    def TransferFromWindow(self):
        return True

    #----------------------------------------------------------------------
    def OnChar(self, event):
        keycode = int(event.GetKeyCode())
        if keycode < 256:
            #print keycode
            key = chr(keycode)
            #print key
            if self.flag == 'no-alpha' and key in string.letters:
                return
            if self.flag == 'no-digit' and key in string.digits:
                return
        event.Skip()

########################################################################
class ValidationDemo(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, wx.ID_ANY, 
                          "Text Validation Tutorial")

        panel = wx.Panel(self)
        textOne = wx.TextCtrl(panel, validator=CharValidator('no-alpha'))
        textTwo = wx.TextCtrl(panel, validator=CharValidator('no-digit'))

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(textOne, 0, wx.ALL, 5)
        sizer.Add(textTwo, 0, wx.ALL, 5)
        panel.SetSizer(sizer)

# Run the program
if __name__ == "__main__":
    app = wx.App(False)
    frame = ValidationDemo()
    frame.Show()
    app.MainLoop()

An alternative approach would be to use Masked controls using wx.lib.masked. The wxPython demo has examples of this as well.

Solution 3

The problem is probably thast you have the ctrl in a panel within the dialog. Set the recursive flag on the dialog to enable validation code to look for controls with validators recursively:

self.SetExtraStyle(wx.WS_EX_VALIDATE_RECURSIVELY)

Solution 4

I was unable to make the sample code work properly within my code (not using a dialog at all but a txtctrl within a panel), even though it works correctly in the demo (go figure).

I ended up using a snippet from another site and feel obligated to document it here:

self.tc.GetValidator().Validate(self.tc)

This was the only way that I could get my custom validator code to be called. Calling self.tc.Validate() did not work at all nor did self.Validate(), nor either representation passing the window in as a parameter.

reference: link text

Share:
13,648
RSK
Author by

RSK

Rubyist / JavaScripter Ex Yeoman Backbone generator maintainer Open source enthusiast Blogger @ PHPRepo and personal blog Coder @ Codemancers Find my presence on web

Updated on June 04, 2022

Comments

  • RSK
    RSK almost 2 years

    I need to validate the textboxes with wx.Textvalidator. Any please help me to do this?

    How can i use wx.FILTER_ALPHA with validators and if the user is giving a wrong input how can i give them a message?

    i need to validate all the inputs when clicking on the save button?

    can any one provide me a sample code for this?

  • RSK
    RSK about 14 years
    But if i need first textbox to restrict alphabets and second text box to restrict numericals then what should i do? whether i need to write two seperate class?
  • Steven Sproat
    Steven Sproat about 14 years
    Yes, ideally you'll place them in some re-usable utility library.