pythonpyqtqlineeditqvalidator

Using QDoubleValidator to limit QLineEdit input and reset the value to nearest acceptable


I would like to use QLineEdit to get user input for values. I want to limit the input between a range so I should use QDoubleValidator. I would like it to work such that if they go over the allowed value, it sets the text to the top() value and if they go under then it sets it to the bottom() value.

I looked at using the textChanged, returnPressed, and inputRejected signals. The reason I am having trouble is that once I set the validator with the range, returnPressed will not enter the check_validator function which they mention here. Then, I thought maybe I could catch it with the input rejected signal but for some reason that doesn't seem to work either. Here is some code:

class LineEdit(QLineEdit):
    def __init__(self, text, parent=None):
        super(LineEdit, self).__init__(parent)
        self.validator = QDouble Validator()
        self.setValidator(self.validator)
        self.text = text
        self.textChanged.connect(self.new_text)
        self.returnPressed(self.check_validator)

    def new_text(self, text):
        self.ntext = text

    def check validator:
        try:
            if float(self.ntext) > self.validator.top():
                self.text = str(self.validator.top()
            if float(self.ntext) < self.validator.bottom():
                self.text = str(self.validator.bottom()
            else:self.text = self.ntext
            self.setText(self.text)
         except:
            mssg = QMessageBox.about(self, "Error", "Input can only be a number")
            mssg.exec()
            self.setText(self.text)

     def valRange(self, x1, x2):
         self.validator.setRange(x1, x2)

I also get an attribute error saying 'noneType' object has no attribute 'exec' when the window does pop up. I think I am missing a step on how to close that window properly.


Solution

  • You could reimplement keyPressEvent to catch return presses when hasAcceptableInput is false. There is also a drawback to overriding the text property, now any programatic calls to setText will not update the text of the QLineEdit. There's no reason to do it.

    class LineEdit(QLineEdit):
        def __init__(self, *args, **kwargs):
            super(LineEdit, self).__init__(*args, **kwargs)
            self.validator = QDoubleValidator(0, 10, 4, notation=QDoubleValidator.StandardNotation)
            self.setValidator(self.validator)
            self.textChanged.connect(self.new_text)
            self.returnPressed.connect(self.check_validator)
            self.ntext = None
    
        def keyPressEvent(self, event):
            super().keyPressEvent(event)
            if event.key() == Qt.Key_Return and not self.hasAcceptableInput():
                self.check_validator()
    
        def new_text(self, text):
            if self.hasAcceptableInput():
                self.ntext = text
    
        def check_validator(self):
            try:
                if float(self.text()) > self.validator.top():
                    self.setText(str(self.validator.top()))
                elif float(self.text()) < self.validator.bottom():
                    self.setText(str(self.validator.bottom()))
            except:
                mssg = QMessageBox.about(self, "Error", "Input can only be a number")
                self.setText(self.ntext)