PyQt5 - QLineEdit正则表达式输入验证器

PyQt5 - QLineEdit正则表达式输入验证器

参考:

https://stackoverflow.com/questions/39202697/qt-qlineedit-input-validation

https://stackoverflow.com/questions/15829782/how-to-restrict-user-input-in-qlineedit-in-pyqt

from PyQt5 import QtWidgets, QtCore, QtGui, Qt
import re



############## QLineEdit正则表达式输入验证器
class LineEditRegExpValidator(QtGui.QValidator):

    '''
    # 默认为科学计数法输入验证器

    用法
    SciNotValidator = LineEditRegExpValidator() # 创建一个QLineEdit正则表达式输入验证器的类,默认为科学计数法输入验证器

    self.LineEdit1.setValidator(SciNotValidator) # 设置验证器(启用)
    self.LineEdit1.installEventFilter(SciNotValidator) # QLineEdit清空内容且游标失焦时,自动填充上一次的字符串内容

    self.LineEdit2.setValidator(SciNotValidator)
    self.LineEdit2.installEventFilter(SciNotValidator)

    self.LineEdit3.setValidator(SciNotValidator)
    self.LineEdit3.installEventFilter(SciNotValidator)

    Validator.validate() is abstract and must be overriddenValidator.validate() is abstract and must be overridden
    '''

    def __init__(
        self, 

        # 编辑状态框输入结束允许的字符串
        fullPatterns=[
            r"[+|-]?[0-9]+\.?[0-9]*(?:[Ee][+|-]?[0-9]+)?", 
            r'[+|-]{0,1}nan', r'[+|-]{0,1}inf'
            ], 
        
        # 编辑状态框输入尚未结束允许的字符串
        partialPatterns=[
            r'[+|-]?[0-9]+\.?[0-9]*(?:[Ee][+|-]?)?', 
            r'-', 
            r'\+', 
            r'[+|-]{0,1}nan', 
            r'[+|-]{0,1}na', 
            r'[+|-]{0,1}n', 
            r'[+|-]{0,1}inf', 
            r'[+|-]{0,1}in', 
            r'[+|-]{0,1}i'
            ],
        
        fixupString='1.0'
        ):

        super(LineEditRegExpValidator, self).__init__()
        self.fullPatterns = fullPatterns
        self.partialPatterns = partialPatterns
        self.fixupString = fixupString
    

    # 实时监听文本框的改变
    # 可能是键盘单个字符'n'输入, 也有可能是粘贴多个字符'nan'输入
    def validate(self, string, pos) -> QtGui.QValidator.State:  # string为编辑状态框中可见的字符串+输入字符/字符串

        # 编辑过程结束,若返回True,将编辑状态框中的字符串填入LineEdit,若返回Flase则自动调用self.fixup方法,将fixup方法返回的字符串填入LineEdit
        if self.acceptable_check(string):
            #print(f'QtGui.QValidator.Acceptable:{QtGui.QValidator.Acceptable}')
            return QtGui.QValidator.Acceptable, string, pos # QtGui.QValidator.Acceptable = 2; 
        

        # 编辑过程中允许出现的字符串
        if self.intermediate_check(string):
            #print(f'QtGui.QValidator.Intermediate:{QtGui.QValidator.Intermediate}')
            return QtGui.QValidator.Intermediate, string, pos # QtGui.QValidator.State = 1;
        # 编辑过程中不允许出现的字符串(本次输入的单个字符或字符串无效)
        else:
            #print(f'QtGui.QValidator.Invalid:{QtGui.QValidator.Invalid}')
            return QtGui.QValidator.Invalid, string, pos


    # 编辑状态框验证通过, 编辑状态框单个字输入符成功
    def acceptable_check(self, string) -> bool:
        True_ = 0
        for fullPattern in self.fullPatterns:
            if re.fullmatch(fullPattern, string):
                True_ += 1
            else:
                continue
        if True_ != 0:
            return True
        else:
            return False

    # 输入还未结束允许的字符串
    def intermediate_check(self, string): #-> bool;    string为编辑状态框中可见的字符串
        """
        Checks if string makes a valid partial float, keeping in mind locale dependent decimal separators.
        """
        if string == '':
            return True
        for partialPattern in self.partialPatterns:
            if re.fullmatch(partialPattern, string):
                return True
            else:
                pass

    # 
    def eventFilter(self, lineEdit, event): # -> bool
        # FocusIn event
        # 每当fous in时,更新LineEditRegExpValidator的fixupString
        # 输入验证器
        '''
        SciNotValidator = LineEditRegExpValidator()

        self.LineEdit1.setValidator(SciNotValidator)
        self.LineEdit1.installEventFilter(SciNotValidator)
        '''

        if event.type() == QtCore.QEvent.FocusIn:
            # do custom stuff
            # print('focus in')

            # self.lineEdit_zhuansu.installEventFilter(SciNotValidator), 在本类中,widget是self.lineEdit,执行函数self.lineEdit.text(),  其它类不一定有text()方法

            #lineEdit.selectAll()
            QtCore.QTimer.singleShot(0, lineEdit.selectAll) # 0ms
            self.fixupString = lineEdit.text()

            #print(self.fixupString)
            # return False so that the lineEdit will also handle the event
            # otherwise it won't focus out
            return False
        else:
            # we don't care about other events
            return False

    # 重写QValidator的fixup(str)方法。可以在切换焦点后,直接修改不合规则的字符串。参数str是经过validate()方法验证后的字符串;
    def fixup(self, string) -> str:
        """
        Fixes up input text to create a valid float. Puts an empty string on failure.
        """
        print(string)

        True_ = 0
        for fullPattern in self.fullPatterns:
            if re.fullmatch(fullPattern, string):
                True_ += 1
            else:
                continue
        if True_ != 0:
            return string
        else:
            return self.fixupString







# listWidget、tableWidget输入数据检查
class LineEditDelegate_Regx(QtWidgets.QStyledItemDelegate):
  # 科学计数法正则表达式
    regx = r"-?\ *[0-9]+\.?[0-9]*(?:[Ee]\ *-?\ *[0-9]+)?"  #
    """
    -?        optionally matches a negative sign (zero or one negative signs)
    \ *       matches any number of spaces (to allow for formatting variations like - 2.3 or -2.3)
    [0-9]+    matches one or more digits
    \.?       optionally matches a period (zero or one periods)
    [0-9]*    matches any number of digits, including zero
    (?: ... ) groups an expression, but without forming a "capturing group" (look it up)
    [Ee]      matches either "e" or "E"
    \ *       matches any number of spaces (to allow for formats like 2.3E5 or 2.3E 5)
    -?        optionally matches a negative sign
    \ *       matches any number of spaces
    [0-9]+    matches one or more digits
    ?         makes the entire non-capturing group optional (to allow for the presence or absence of the exponent - 3000 or 3E3

    https://stackoverflow.com/questions/18152597/extract-scientific-number-from-string
    """

    """
    用法:
    def __init__(self, parent=None):
        super(NewClassName, self).__init__(parent)
        self.setupUi(self)

        delegate = LineEditDelegate_Regx(regx=None)
        self.listWidget_ShuZhiLieBiao.setItemDelegate(delegate)
        self.tableWidget.setItemDelegate(delegate)
    """
    def __init__(self, regx=None, parent=None):
        super(LineEditDelegate_Regx, self).__init__(parent)
        if regx == None:
            pass
        else:
            self.regx = regx

    # 方法重写
    def createEditor(self, parent, option, index): # self, parent, option, index四个参数均不能少
        editor_qlineedit = QtWidgets.QLineEdit(parent)
        #SciNotValidator = QtGui.QRegExpValidator(QtCore.QRegExp(self.regx))
        SciNotValidator = LineEditRegExpValidator()
        editor_qlineedit.setValidator(SciNotValidator)
        return editor_qlineedit #  LineEditDelegate_Regx(regx=None, parent=None), QStyledItemDelegate(parent: QObject = None)




"""

# LineEdit输入数据检查
def LineEditInputChecking(lineEdit, regx=None):
    '''
    用法:
    LineEditInputChecking(lineEdit=self.lineEdit_zhuansu)
    '''
    if regx == None:
        regx = r"-?\ *[0-9]+\.?[0-9]*(?:[Ee]\ *-?\ *[0-9]+)?"
    reg_ex = QtCore.QRegExp(regx)
    input_validator = QtGui.QRegExpValidator(reg_ex, lineEdit)
    lineEdit.setValidator(input_validator)


"""




©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容