User Input Validation in PyQt5 and Python

Question:

This is a two part question about input validation with one specific and another more general component.

The specific:

While researching the topic, I found THIS on Regular Expressions.
I realize that the code in this post is using PyQt4. However I wanted to get this working with PyQt5, since I had already started my project with it. (Obviously blindly – I can only find C++ documentation for it)

This is what I tried:

# somewhere above:     
self.le_input = QtWidgets.QLineEdit()

# at some point validate_input gets called:
# more on that in the second part of this question

def validate_input(self):
    reg_ex = QtCore.QRegExp(""[0-9]+.?[0-9]{,2}"")
    input_validator = QtGui.QRegExpValidator(reg_ex, self.le_input.text())
    self.le_input.setValidator(input_validator)

When I run the code I get the following Error:

QRegExpValidator(parent: QObject = None): argument 1 has unexpected type ‘QRegExp’
QRegExpValidator(QRegExp, parent: QObject = None): argument 2 has unexpected type ‘str’

Aren’t these exactly the required arguments?
Does anyone know how to get this working?


The general:

What is an effective way to implement live validation with PyQt in Python?

At the moment I would use:

self.le_input.textChanged.connect(self.validate_input)

This does work, but as soon as I try to connect two QtLineEdits, that affect each other, to the same slot, things stop working because “textChanged” gets called by both of them at the same time.

Use case: Two input fields: Amount before TAX and Amount after TAX – and whichever you enter automatically fills the other one while typing.

First validation, then calculation, then output to the other field.

Many thanks in advance! Any help is highly appreciated!

Asked By: michaelh

||

Answers:

You can set different validators for different QLineEdit objects.

QRegExpValidator has two constructors:

QRegExpValidator(parent: QObject = None)
QRegExpValidator(QRegExp, parent: QObject = None)

so, you should change your code to:

reg_ex = QRegExp("[0-9]+.?[0-9]{,2}")
input_validator = QRegExpValidator(reg_ex, self.le_input)
self.le_input.setValidator(input_validator)

Once you set validator for QLineEdit, there is no need to use

self.le_input.textChanged.connect(self.validate_input)

Just delete it. And that should work fine.

If you want to find documentation about PyQt5, you can simple use this in your console:

pydoc3 PyQt5.QtGui.QRegExpValidator

But pydoc can only show you little information, so you should use C++ version documation as well.

Finally, an example about this:

from PyQt5.Qt import QApplication
from PyQt5.QtCore import QRegExp
from PyQt5.QtGui import QRegExpValidator
from PyQt5.QtWidgets import QWidget, QLineEdit

import sys

class MyWidget(QWidget):
    def __init__(self, parent=None):
        super(QWidget, self).__init__(parent)
        self.le_input = QLineEdit(self)

        reg_ex = QRegExp("[0-9]+.?[0-9]{,2}")
        input_validator = QRegExpValidator(reg_ex, self.le_input)
        self.le_input.setValidator(input_validator)

if __name__ == '__main__':
    a = QApplication(sys.argv)

    w = MyWidget()
    w.show()

    a.exec()
Answered By: September

Either methods seems to work well with input validation except for textChanged() signal when two lineEdits which affects each other when using the same slot function .However I have a comment on QRegExpValidator, it may scare the user to think their keyboard is not working since trying to type anything not allowed shows nothing(no interaction whatsoever) while using textChanged() signal can allow some interaction using some statements in the slot function. Any thoughts on my view above? How can I address this? @eyllanesc

I have made my conclusion by trying this code example shared above and many other examples I may not be able to share:

from PyQt5.Qt import QApplication
from PyQt5.QtCore import QRegExp
from PyQt5.QtGui import QRegExpValidator
from PyQt5.QtWidgets import QWidget, QLineEdit

import sys

class MyWidget(QWidget):
    def __init__(self, parent=None):
        super(QWidget, self).__init__(parent)
        self.le_input = QLineEdit(self)

        reg_ex = QRegExp("[0-9]+.?[0-9]{,2}")
        input_validator = QRegExpValidator(reg_ex, self.le_input)
        self.le_input.setValidator(input_validator)

if __name__ == '__main__':
    a = QApplication(sys.argv)

    w = MyWidget()
    w.show()

    a.exec()
Answered By: Kelvin
# for PySide2
from PySide2 import QtCore, QtGui, QtWidgets

from PySide2.QtWidgets import *

from PySide2.QtGui import QFont, QColor, QRegExpValidator

from PySide2.QtCore import Qt, QRegExp


class MyWidget(QWidget):

    def __init__(self):

        super().__init__()


        def validator(valid):
            reg_ex = QRegExp(valid)
            vld = QRegExpValidator(reg_ex, self.le_input)
            return vld

        self.le_input = QLineEdit(self)
        val = "[0-9]+.?[0-9]{,2}"
        self.le_input.setValidator(validator(val))


a = QApplication([])

w = MyWidget()

w.show()

a.exec_()
Answered By: alexgurd
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.