I'm trying to write my first validator for wxPython. I want to check the TextCtrl value and change its background color based on whether or not it's numeric. It kind of works, except the event triggers before the current character is actually put in, so the validation is always one character behind. Here's my code:

class Validate_Numeric ( wx . PyValidator ):
	def __init__ ( Self ):
		wx . PyValidator . __init__ ( Self )
		Self . Bind ( wx . EVT_TEXT, Self . On_Text_Change )
	def Clone ( Self ):
		return Validate_Numeric ()
	def On_Text_Change ( Self, Event ):
		TextCtrl = Self . GetWindow ()
		Text = TextCtrl . GetValue ()
		if Text . isdigit() or Text == "":
			TextCtrl . SetBackgroundColour ( "White" )
		else :
			TextCtrl . SetBackgroundColour ( "Pink" )
		Event . Skip ()

Questionable_TextCtrl = wx . TextCtrl ( Self, wx . ID_ANY, validator = Validate_Numeric () )

I've also tried EVT_CHAR and EVT_KEY_UP, but they all behave the same way. Does anybody know what I can do to validate the text after the text is updated?

Thanks!

Recommended Answers

All 4 Replies

class Validate_Numeric ( wx . PyValidator ):
	def __init__ ( Self ):
		wx . PyValidator . __init__ ( Self )
	def Clone ( Self ):
		return Validate_Numeric ()
	def On_Text_Change ( Self, Event ):
		TextCtrl = Self . GetWindow ()
		Text = TextCtrl . GetValue ()
		if Text . isdigit() or Text == "":
			TextCtrl . SetBackgroundColour ( "White" )
		else :
			TextCtrl . SetBackgroundColour ( "Pink" )
		Event . Skip ()

Questionable_TextCtrl = wx . TextCtrl ( Self, wx . ID_ANY, validator = Validate_Numeric () )

Try removing the Binding statement all together. You don't need to bind a validator to enable it. If you declare it under the validator paramater of TextCtrl it should work automagically; however you may need to change the name of your On_Text_Change method to Validate . I've been outta the wx game for a while but I believe that's required...

Here's a Validator I've used in the past to force the user to enter values into certain TextCtrls:

class TextValidator(wx.PyValidator):
    def __init__(self):
        wx.PyValidator.__init__(self)
    def Clone(self): # Required method for validator
        return TextValidator()
    def TransferToWindow(self):
        return True # Prevent wxDialog from complaining.
    def TransferFromWindow(self):
        return True # Prevent wxDialog from complaining.

    def Validate(self, win):
        textCtrl = self.GetWindow()
        text = textCtrl.GetValue()

        if len(text) == 0:
            wx.MessageBox("Text input is required", "Error")
            textCtrl.SetBackgroundColour("pink")
            textCtrl.SetFocus()
            textCtrl.Refresh()
            return False
        else:
            textCtrl.SetBackgroundColour(
                wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
            textCtrl.Refresh()
            return True

Try removing the Binding statement all together. You don't need to bind a validator to enable it. If you declare it under the validator paramater of TextCtrl it should work automagically; however you may need to change the name of your On_Text_Change method to Validate . I've been outta the wx game for a while but I believe that's required...

Here's a Validator I've used in the past to force the user to enter values into certain TextCtrls:

Thank you very much for the feedback!

I just tried this, but Validate () doesn't ever seem to run. I had seen that on a few other examples and thought it might be the default method, but none of my attempts have ever triggered it.

Bare bones for the whole program:

import wx

class Validate_TextCtrl ( wx . PyValidator ):
	def __init__ ( Self ):
		wx . PyValidator . __init__ ( Self )
	def Clone ( Self ):
		return Validate_TextCtrl ()
	def TransferToWindow ( Self ):
		return True
	def TransferFromWindow ( Self ):
		return True
	def Validate ( Self, Win ):
		print ( "Validate" )
		return True

class Main_Window ( wx . Frame ):
	def __init__ ( Self, Parent ):
		wx . Frame . __init__ ( Self, Parent, wx . ID_ANY )
		Self . Questionable_TextCtrl = wx . TextCtrl ( Self, wx . ID_ANY, "", validator = Validate_TextCtrl () )
		Self . Show ( True )

Application = wx . PySimpleApp ()
Frame = Main_Window ( None )
Application . MainLoop ()

No love. :( Any idea what I might be doing wrong?

(Python 2.6.2 and wxPython 2.8 on Windows XP, if it matters.)

Using tabs for indentation makes your code look so ugly. Can't you just use 4 spaces like most other people?

Also, by convention only class names start with a capital letter.

by convention only class names start with a capital letter.

I'm pretty sure the OP couldn't care less about convention. His coding style is quite unique:

My coding style is on purpose. I put great emphasis on human readability, which comes out in many ways, including generous whitespace.

I guess part of that "human readability" becomes capitalizing every parameter name as well.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.