I want to have a text control that only accepts numbers. (Just integer values like 45 or 366)
What is the best way to do this?
I want to have a text control that only accepts numbers. (Just integer values like 45 or 366)
What is the best way to do this?
I had to do something similar, checking for alphanumeric codes. The tip on EVT_CHAR was the right thing:
class TestPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
self.entry = wx.TextCtrl(self, -1)
self.entry.Bind(wx.EVT_CHAR, self.handle_keypress)
def handle_keypress(self, event):
keycode = event.GetKeyCode()
if keycode < 255:
# valid ASCII
if chr(keycode).isalnum():
# Valid alphanumeric character
event.Skip()
IntCtrl
, Masked Edit Control
, and NumCtrl
are all designed to do just this, with different levels of control. Checkout the wx demo under "More Windows/Controls" to see how they work.
(Or, if you're instead really looking forward to doing this directly with a raw TextCtrl, I think you'd want to catch EVT_CHAR events, test the characters, and call evt.Skip() if it was an allowed character.)
As other answers note, it's possible to do this with an EVT_CHAR
handler. You'll want to call event.Skip()
for the characters you want to let through, and not call it for the ones you want to block. One nuance is that you probably also want to call event.Skip()
for tab characters; pressing tab triggers the EVT_CHAR
event, and if you don't call event.Skip()
, you'll effectively disable tab traversal between TextCtrl
s.
Here's a minimal application showing two TextCtrl
s that accept integer or decimal numbers, with working tab traversal:
import wx
app = wx.App()
frame = wx.Frame(None, -1, 'simple.py')
panel = wx.Panel(frame)
text_ctrl_1 = wx.TextCtrl(panel, value='123')
text_ctrl_2 = wx.TextCtrl(panel, value='456', pos=(0, 30))
def block_non_numbers(event):
key_code = event.GetKeyCode()
# Allow ASCII numerics
if ord('0') <= key_code <= ord('9'):
event.Skip()
return
# Allow decimal points
if key_code == ord('.'):
event.Skip()
return
# Allow tabs, for tab navigation between TextCtrls
if key_code == ord('\t'):
event.Skip()
return
# Block everything else
return
text_ctrl_1.Bind(wx.EVT_CHAR, block_non_numbers)
text_ctrl_2.Bind(wx.EVT_CHAR, block_non_numbers)
frame.Show()
app.MainLoop()
You can try IntCtrl
, EVT_CHAR
, or implement a new/existing validator (like IntValidator). Validators can be used to validate a field (useful when trying to validate multiple things on a dialog/panel) and they can also be used with EVT_CHAR to restrict input in a field.
I wanted the same but for floats, so I used the following method in the class:
def force_numeric(self, event, edit):
raw_value = edit.GetValue().strip()
keycode = event.GetKeyCode()
if keycode < 255:
print('keycode:', keycode,'chr(keycode) ', chr(keycode))
if chr(keycode).isdigit() or chr(keycode)=='.' and '.' not in raw_value:
print('skip')
event.Skip()
to register the event in the constructor:
item = wx.TextCtrl(self.panel, -1, str(pose_config['locref_stdev']))
item.Bind(wx.EVT_CHAR, lambda event: self.force_numeric(event, item))
Modifying the answer above
NumCtrl has some weird quirks to me. Here is my attempt to create a Number control based on EVT_CHAR and keycode.
This control allow numbers as well as all special keycode (ctrl combo, arrow key, backspace etc...), so that copy-paste, undo-redo, select-all etc still works. It will only block other printable characters (using string.printable) and unicode characters (using WXK_NONE)
Another way to check and allow all special keycode can be found by this answer. This is a better approach but requires more code.
import string
MyNumCtrl = wx.TextCtrl()
MyNumCtrl.Bind(EVT_CHAR, onChar)
def onChar(self, event):
keycode = event.GetKeyCode()
obj = event.GetEventObject()
val = obj.GetValue()
# filter unicode characters
if keycode == wx.WXK_NONE:
pass
# allow digits
elif chr(keycode) in string.digits:
event.Skip()
# allow special, non-printable keycodes
elif chr(keycode) not in string.printable:
event.Skip() # allow all other special keycode
# allow '-' for negative numbers
elif chr(keycode) == '-':
if val[0] == '-':
obj.SetValue(val[1:])
else:
obj.SetValue('-' + val)
# allow '.' for float numbers
elif chr(keycode) == '.' and '.' not in val:
event.Skip()
return
Please check "Validator.py" script in wxpython demo. it is exactly what you need