Можно ли ограничить TextCtrl приемом чисел только в wxPython?

Я хочу иметь текстовый элемент управления, который принимает только цифры. (Просто целочисленные значения, такие как 45 или 366)

Каков наилучший способ сделать это?

6 ответов

Решение

IntCtrl, Masked Edit Control, а также NumCtrl все они предназначены именно для этого, с разными уровнями контроля. Ознакомьтесь с демоверсией wx в разделе "Больше окон / элементов управления", чтобы увидеть, как они работают.

(Или, если вы вместо этого действительно хотите сделать это напрямую с необработанным TextCtrl, я думаю, вы захотите перехватить события EVT_CHAR, проверить символы и вызвать evt.Skip(), если это был разрешенный символ.)

Я должен был сделать что-то подобное, проверяя буквенно-цифровые коды. Совет на EVT_CHAR был правильным:

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()

Я хотел того же, но для чисел с плавающей запятой, поэтому в классе использовал следующий метод:

 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()

для регистрации события в конструкторе:

    item = wx.TextCtrl(self.panel, -1, str(pose_config['locref_stdev']))
    item.Bind(wx.EVT_CHAR, lambda event: self.force_numeric(event, item))

Изменение ответа выше

Ты можешь попробовать IntCtrl, EVT_CHARили внедрить новый / существующий валидатор (например, IntValidator). Валидаторы можно использовать для проверки поля (полезно при попытке проверить несколько объектов в диалоговом окне / панели), а также их можно использовать с EVT_CHAR для ограничения ввода в поле.

Как отмечают другие ответы, это можно сделать с EVT_CHAR обработчик. Вы хотите позвонить event.Skip() для символов, которых вы хотите пропустить, а не вызывать его для тех, кого вы хотите заблокировать. Один нюанс в том, что вы, вероятно, тоже хотите позвонить event.Skip() для символов табуляции; нажатие на вкладку вызывает EVT_CHAR событие, и если вы не позвоните event.Skip()вы эффективно отключите обход табуляции между TextCtrls.

Вот минимальное приложение, показывающее два TextCtrls, которые принимают целые или десятичные числа, с рабочим обходом табуляции:

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()

NumCtrl имеет некоторые странные причуды для меня. Вот моя попытка создать элемент управления Number на основе EVT_CHAR и кода ключа.

Этот элемент управления позволяет использовать числа, а также весь специальный код клавиши (комбинация клавиш ctrl, клавишу со стрелкой, клавишу возврата и т. Д.), Так что копирование-вставка, отмена-повтор, выбор-все и т. Д. Все еще работает. Он будет блокировать только другие печатные символы (используя string.printable) и символы Юникода (используя WXK_NONE)

Этот ответ может найти другой способ проверить и разрешить все специальные коды клавиш. Это лучший подход, но требует больше кода.

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

Пожалуйста, проверьте скрипт "Validator.py" в демоверсии wxpython. это именно то, что вам нужно

Другие вопросы по тегам