wxPython中是否可以限制TextCtrl只接受数字?

问题描述 投票:0回答:8

我想要一个只接受数字的文本控件。 (只是整数值,如 45 或 366)

最好的方法是什么?

wxpython textctrl
8个回答
10
投票

我必须做类似的事情,检查字母数字代码。 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()

7
投票

IntCtrl
Masked Edit Control
NumCtrl
都旨在实现此目的,并具有不同级别的控制。 查看“更多 Windows/控件”下的 wx 演示,了解它们是如何工作的。

(或者,如果您确实希望直接使用原始 TextCtrl 执行此操作,我认为您需要捕获 EVT_CHAR 事件,测试字符,并调用 evt.Skip() (如果它是允许的字符)。 )


1
投票

您可以尝试

IntCtrl
EVT_CHAR
,或实现新的/现有的验证器(如 IntValidator)。验证器可用于验证字段(在尝试验证对话框/面板上的多个内容时很有用),它们也可以与 EVT_CHAR 一起使用来限制字段中的输入。


1
投票

正如其他答案所指出的,可以使用

EVT_CHAR
处理程序来完成此操作。您需要为您想要让其通过的角色调用
event.Skip()
,而不是为您想要阻止的角色调用它。一个细微差别是,您可能还想为制表符调用
event.Skip()
;按 Tab 会触发
EVT_CHAR
事件,如果不调用
event.Skip()
,您将有效地禁用
TextCtrl
之间的 Tab 遍历。

这是一个最小的应用程序,显示两个接受整数或小数的

TextCtrl
,并具有工作选项卡遍历功能:

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

1
投票

我想要相同的但对于浮点数,所以我在类中使用了以下方法:

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

修改上面的答案


0
投票

NumCtrl 对我来说有一些奇怪的怪癖。这是我尝试创建基于 EVT_CHAR 和键码的数字控件。

此控件允许数字以及所有特殊键码(ctrl组合、箭头键、退格键等),因此复制粘贴、撤消重做、全选等仍然有效。它只会阻止其他可打印字符(使用string.printable)和unicode字符(使用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

0
投票

您好,您可以在此处使用此侦听器来绑定您的 TxtCtrl。

就做:

self.__MyTxtCtrl.Bind(wx.EVT_CHAR, self.__on_change_text_check_is_int_value)


def __on_change_text_check_is_int_value(self, evt):
        KeyboardEventUtils.on_change_text_check_is_int_value(self, evt)

并使用这个类:

from pyglet.window import key

FLOAT_POINT = "."

ENTRY_ID = "id"
ENTRY_KEY_EVENT = "keyEvent"
ENTRY_SELECTION_EVENT = "selectionEvent"

MASK_STARTED_RIGHT_SELECTION = 1
MASK_STARTED_LEFT_SELECTION = -1

class KeyboardEventUtils(object):

    __mLastEvt = {}

    def check_input_key_only_numeric_value(value, strng):
        return value.isnumeric() or (value == FLOAT_POINT and not FLOAT_POINT in strng and len(strng) > 0)

    def on_change_text_check_is_int_value(self, evt):
        txt = evt.GetEventObject()
        value = chr(evt.GetUnicodeKey())

        if KeyboardEventUtils.__mLastEvt != None and len(KeyboardEventUtils.__mLastEvt) > 0 and KeyboardEventUtils.__mLastEvt[ENTRY_ID] != txt.GetId():
            self._mLastEvt = ()

        if check_input_key_only_numeric_value(value, txt.GetValue()):
            pos = txt.GetInsertionPoint()
            txt.SetValue(txt.GetValue()[:pos] + value + txt.GetValue()[pos:])
            txt.SetInsertionPoint(pos + 1)

        elif (evt.GetModifiers() == 4 or evt.GetModifiers() == key.MOD_SHIFT) and evt.GetRawKeyCode() == key.LEFT:            # 4 (?) key.MOD_SHIFT (?)              TO FIX
            pos = txt.GetInsertionPoint()
            rng = list(txt.GetSelection())

            if rng[0] == rng[1] and ENTRY_SELECTION_EVENT in KeyboardEventUtils.__mLastEvt:
                del KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT]

            if ENTRY_SELECTION_EVENT in KeyboardEventUtils.__mLastEvt and KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT] == MASK_STARTED_RIGHT_SELECTION:

                rng[1] = rng[1] - 1
            else:
                KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT] = MASK_STARTED_LEFT_SELECTION
                rng[0] = rng[0] - 1

            txt.SetSelection(rng[0], rng[1])

        elif (evt.GetModifiers() == 4 or evt.GetModifiers() == key.MOD_SHIFT):            # 4 (?) key.MOD_SHIFT (?)             TO FIX
            pos = txt.GetInsertionPoint()
            rng = list(txt.GetSelection())

            if rng[0] == rng[1] and ENTRY_SELECTION_EVENT in KeyboardEventUtils.__mLastEvt:
                del KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT]

            if ENTRY_SELECTION_EVENT in KeyboardEventUtils.__mLastEvt and KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT] == MASK_STARTED_LEFT_SELECTION:
                rng[0] = rng[0] + 1
            else:
                KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT] = MASK_STARTED_RIGHT_SELECTION
                rng[1] = rng[1] + 1

            txt.SetSelection(rng[0], rng[1])

        elif evt.GetRawKeyCode() == key.LEFT:
            rng = list(txt.GetSelection())

            if rng[0] != rng[1]:
                txt.SetInsertionPoint(rng[0])
            else:
                txt.SetInsertionPoint(txt.GetInsertionPoint() - 1)

        elif evt.GetRawKeyCode() == key.RIGHT:
            rng = list(txt.GetSelection())

            if rng[0] != rng[1]:
                txt.SetInsertionPoint(rng[1])
            else:
                txt.SetInsertionPoint(txt.GetInsertionPoint() + 1)

        elif evt.GetRawKeyCode() == key.UP or evt.GetRawKeyCode() == key.DOWN:
            pass

        elif evt.GetRawKeyCode() == key.BACKSPACE:                                              
            pos = txt.GetInsertionPoint()
            if txt.GetStringSelection() == "":
                txt.SetValue(txt.GetValue()[:pos-1] + txt.GetValue()[pos:])
                txt.SetInsertionPoint(pos - 0x1)
            else:
                r = txt.GetSelection()
                txt.SetValue(txt.GetValue()[:r[0]] + txt.GetValue()[r[1]:])
                txt.SetInsertionPoint(pos)

        elif evt.GetRawKeyCode() == key.DELETE:
            pos = txt.GetInsertionPoint()
            if txt.GetStringSelection() == "":
                txt.SetValue(txt.GetValue()[:pos] + txt.GetValue()[pos+1:])
            else:
                r = txt.GetSelection()
                txt.SetValue(txt.GetValue()[:r[0]] + txt.GetValue()[r[1]:])
            txt.SetInsertionPoint(pos)

        elif evt.GetModifiers() == key.MOD_CTRL and evt.GetRawKeyCode() == key.A:
            txt.SelectAll()

        else:

            KeyboardEventUtils.__mLastEvt[ENTRY_ID] = txt.GetId()
            KeyboardEventUtils.__mLastEvt[ENTRY_KEY_EVENT] = evt
            return False

        KeyboardEventUtils.__mLastEvt[ENTRY_ID] = txt.GetId()
        KeyboardEventUtils.__mLastEvt[ENTRY_KEY_EVENT] = evt
        return True

-1
投票

请检查wxpython demo中的“Validator.py”脚本。这正是您所需要的

© www.soinside.com 2019 - 2024. All rights reserved.