Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • Unsolved
Collapse
qtws26_logo

The Qt Event of the Year: Qt World Summit 2026

Save Your Spot >
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Validate QLineEdit before changing focus
Qt 6.12 LTS is out! See what's new in the release blog

Validate QLineEdit before changing focus

Scheduled Pinned Locked Moved Solved Qt for Python
11 Posts 3 Posters 7.1k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • JonBJ Online
    JonBJ Online
    JonB
    wrote on last edited by JonB
    #2
    • Can't you write your own QValidator::State QValidator::validate(QString &input, int &pos) const override to do what you want? So far as I know, if that returns "invalid" the focus stays in the edit widget. You can probably start from QValidator::State QIntValidator::validate(QString &input, int &pos) const to get the integer validation, and add your own logic to check the value from the database?

    • If, for whatever reason, you don't do it with a validator (e.g. you write your own code on editing finished), you can always put the focus back to the widget on failure in your own code?

    1 Reply Last reply
    2
    • J Offline
      J Offline
      jdsantos1978
      wrote on last edited by
      #3

      Hi JonB. Thanks for your response.
      As long as I know QValidator validates every single key stroke, and I want to validate only when the user has finished typing and the focus is going to the next Widget.
      I've trying writing a slot for the editingFinished signal and it works, but only if the field is edited. I mean, an empty field doesnt fire the editingFinished signal, or if I try something wrong, I can check that it's wrong and I send the focus back to the QLineEdit, but if the user doesn't change the text again, editingFinished wont be fired again.
      I thought that the correct way of handling this was with an EvenFilter capturing, for example, the FocusAboutToChange event, like this:

      class Filter(QtCore.QObject):
          def __init__(self):
              super(Filter, self).__init__()
      
          def eventFilter(self, object: 'QObject', a1: 'QEvent') -> bool:
              if a1.type() in [QtCore.QEvent.Type.FocusAboutToChange]:
                  if validation_is_wrong():
                      return True
      
              return False
      

      and installing the event filter in the LineEdit:

      self._filter = Filter()
              self.led_nombre_empresa = QtWidgets.QLineEdit()
              self.led_nombre_empresa.installEventFilter(self._filter)
      

      But it doesn't work as I expected.

      JonBJ 1 Reply Last reply
      0
      • J jdsantos1978

        Hi JonB. Thanks for your response.
        As long as I know QValidator validates every single key stroke, and I want to validate only when the user has finished typing and the focus is going to the next Widget.
        I've trying writing a slot for the editingFinished signal and it works, but only if the field is edited. I mean, an empty field doesnt fire the editingFinished signal, or if I try something wrong, I can check that it's wrong and I send the focus back to the QLineEdit, but if the user doesn't change the text again, editingFinished wont be fired again.
        I thought that the correct way of handling this was with an EvenFilter capturing, for example, the FocusAboutToChange event, like this:

        class Filter(QtCore.QObject):
            def __init__(self):
                super(Filter, self).__init__()
        
            def eventFilter(self, object: 'QObject', a1: 'QEvent') -> bool:
                if a1.type() in [QtCore.QEvent.Type.FocusAboutToChange]:
                    if validation_is_wrong():
                        return True
        
                return False
        

        and installing the event filter in the LineEdit:

        self._filter = Filter()
                self.led_nombre_empresa = QtWidgets.QLineEdit()
                self.led_nombre_empresa.installEventFilter(self._filter)
        

        But it doesn't work as I expected.

        JonBJ Online
        JonBJ Online
        JonB
        wrote on last edited by
        #4

        @jdsantos1978 said in Validate QLineEdit before changing focus:

        But it doesn't work as I expected.

        You should explain what you mean by that. Do you receive the focus event?

        1 Reply Last reply
        0
        • J Offline
          J Offline
          jdsantos1978
          wrote on last edited by
          #5

          I've written an small example.

          I shouldn't be able to type in the second QLineEdit until "123" is typed in the first one.

          Acording to doc, eventfilter should return True if i want the event to be stopped:

          from PyQt6 import QtWidgets, QtCore, QtGui
          import sys
          
          class MyWindow(QtWidgets.QWidget):
              def __init__(self):
                  super(MyWindow, self).__init__()
          
                  self.__add_widgets()
                  self.setGeometry(300,200,300,200)
          
              def __add_widgets(self):
                  self.edit_id = QtWidgets.QLineEdit()
                  self.lbl_name = QtWidgets.QLabel("Name goes here...")
                  self.edit_other = QtWidgets.QLineEdit("Cannot enter here until 123 in first QLineEdit")
          
                  vbox = QtWidgets.QVBoxLayout()
                  vbox.addWidget(self.edit_id)
                  vbox.addWidget(self.lbl_name)
                  vbox.addWidget(self.edit_other)
          
                  self.setLayout(vbox)
                  self.edit_id.installEventFilter(self)
          
              def eventFilter(self, object: QtCore.QObject, event: QtCore.QEvent) -> bool:
                  if object == self.edit_id:
                      if event.type() == QtCore.QEvent.Type.FocusAboutToChange:
                          if not self.__validate_id():
                              print ("Not good :(")
                              self.edit_id.setFocus()
                              return True
                          else:
                              print ("Good :)")
                              return False
          
                  return super().eventFilter(object, event)
          
          
              def __validate_id(self) -> bool:
                  customer_id = self.edit_id.text()
                  if customer_id == "123":
                      self.lbl_name.setText("Pepito Pérez")
                      return True
                  else:
                      self.lbl_name.setText("Unknown Customer")
                      return False
          
          app = QtWidgets.QApplication(sys.argv)
          window = MyWindow()
          window.show()
          sys.exit(app.exec())
          
          
          1 Reply Last reply
          0
          • SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by SGaist
            #6

            Hi,

            One design question: why allow your user to access anything that requires that id to be valid ?

            It rather looks that there should be an explicit check like when you log into a database.

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            0
            • J Offline
              J Offline
              jdsantos1978
              wrote on last edited by
              #7

              Hi.

              I know that most of the validation of a form can be done in a "Ok" Button, but think in the following example (it's a java app):

              example.png

              In all the "Cta." fields:

              • I want the user to write a valid Id. That can be validated at the OK. Button.
              • I want the user to write an Id (not empty). That can be done at the Ok Button.
              • I want to give the user the posibility of creating a new "Cta." if the id he has entered doesn't exist in the database.

              This last behaviour could be achieved handling the FocusOut signal but:

              • I would probably have interferences handling FocusOut of all those fields.
              • I wouldn't want any validation if the Search Button or Cancel Button where pressed.

              It would be great to have a "validate" signal in the widgets before the focus signals, and a causes_validation (True / False) flag in the widgets to handle this.

              Anyway, I've figured out a way of achieving this handling the Focus Events. I have to work it out a little and I'll post it here.

              1 Reply Last reply
              0
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #8

                Maybe a custom QValidator ?

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply
                0
                • J Offline
                  J Offline
                  jdsantos1978
                  wrote on last edited by
                  #9

                  Thanks SGaist.

                  As I said before, QValidator validates every single stroke, and I want a final validation before passing the focus.

                  Probably the best approach is to write and intall an EvenFilter that handles the QtCore.QEvent.Type.FocusAboutToChange event:

                  "When the filter object’s eventFilter() implementation is called, it can accept or reject the event, and allow or deny further processing of the event. If all the event filters allow further processing of an event (by each returning false), the event is sent to the target object itself. If one of them stops processing (by returning true), the target and any later event filters do not get to see the event at all."

                  The problem is that although I stop the FocusAboutToChange event, even the FocusOut event in the widget, it doesn't stop firing those same events in the next Widget, and that's precisely what I want to avoid.

                  1 Reply Last reply
                  0
                  • SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on last edited by
                    #10

                    Can you show your event filter ?

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    1 Reply Last reply
                    0
                    • J Offline
                      J Offline
                      jdsantos1978
                      wrote on last edited by
                      #11

                      It's a workaround, but it's working for me just now.

                      The idea is using two EventFilters :

                      • A normal Filter.
                      • A temporary Filter.

                      The "normal" filter installs the temporary filter in widget that is going to be focused next when processing the FocusOut event. The only thing that the temporary filter does is to accept all the focus events and stop them.

                      The temporary filter removes itself from the widget in the FocusOut event.

                      This way, the "normal" filter can do internal and external validations before losing the focus.

                      I'm doing some tests and it's working for me. I want to implement it inside a custum widget.

                          class DYFieldEventFilter(QtCore.QObject):
                      
                              class TemporaryFilter(QtCore.QObject):
                                  def __init__(self):
                                      super(DYField.DYFieldEventFilter.TemporaryFilter, self).__init__()
                      
                                  def eventFilter(self, widget: 'QObject', event: 'QEvent') -> bool:
                                      focus_events = {
                                          QtCore.QEvent.Type.FocusAboutToChange: "FocusAboutToChange",
                                          QtCore.QEvent.Type.FocusIn: "FocusIn",
                                          QtCore.QEvent.Type.FocusOut: "FocusOut",
                                      }
                      
                                      if event.type() in focus_events:
                                          event.accept()
                      
                                          if event.type() == QtCore.QEvent.Type.FocusOut:
                                              widget.removeEventFilter(self)
                      
                                          return True
                      
                                      return False
                      
                              def __init__(self, field):
                                  super(DYField.DYFieldEventFilter, self).__init__()
                                  self.field = field
                      
                              def eventFilter(self, widget: 'QObject', event: QtCore.QEvent) -> bool:
                      
                                  if event.type() == QtCore.QEvent.Type.FocusOut:
                      
                                      # Internal validation.
                                      self.field.validate_field()
                      
                                      # External validation.
                                      self.field.validate.emit()
                      
                                      if not self.field.valid():
                                          # If the content of the widget is not valid, focus will be kept on it.
                                          # To achieve that, when focusing out, we install a TemporaryEventFilter in the next focused
                                          # widget to accept and stop all the Focus Events.
                                          # That filter will be removed in the FocusOut event of the TemporaryEventFilter.
                                          next_focused = QtWidgets.QApplication.focusWidget()
                                          temp_filter = DYField.DYFieldEventFilter.TemporaryFilter()
                                          if next_focused:
                                              next_focused.installEventFilter(temp_filter)
                      
                                          event.accept()
                      
                                          widget.setFocus()
                                          widget.selectAll()
                      
                                          return True
                      
                                  return False
                      
                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt
                      • Unsolved