Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. FocusOutEvent get stuck in a loop
Forum Updated to NodeBB v4.3 + New Features

FocusOutEvent get stuck in a loop

Scheduled Pinned Locked Moved Unsolved Qt for Python
7 Posts 3 Posters 706 Views
  • 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.
  • B Offline
    B Offline
    BretO
    wrote on 22 Apr 2025, 12:20 last edited by
    #1

    I'm working on a PYQT app and have two lineEdit boxes (line_edit1 and line_edit2) with input masks. Since editingFinished only triggers if the input mask is complete it looks like I need to create a custom focusOutEvent to be able to check if the user leaves the box before they complete the full input mask and set the focus back in that lineEdit. The problem is it seems the focusOutEvent is getting stuck in a loop if I have both custom lineEdits right after each other. If I put a normal lineEdit (line_edit3) between 1 and 2 then everything works as expected.

    In watching the debug with line_edit1 and 2 together when I enter the first character in line_edit1 it goes to my on_text_changed1 function and evaluates if it has the correct number of characters and prints out the status. It then immediately goes to the custom focusOutEvent for line_edit1 and checks. (Not sure why since this should only be checking for the text changed and not a focus out) and then goes to line_edit2 and checks it's focusOutEvent and back to line_edit1 again and into a loop until it crashes.

    If I have line_edit3 in between 1 and 2 then it does not bounce back and forth between the focusOutEvent of 1 and 2.

    Maybe I have not done the custom focusOutEvent correctly?
    Any help would be appreciated.

    from PyQt6.QtWidgets import QApplication, QLineEdit, QWidget, QVBoxLayout
    from PyQt6.QtGui import QFocusEvent
    
    class CustomLineEdit1(QLineEdit):
            def __init__(self, parent=None):
               super().__init__(parent)
    
            def focusOutEvent(self, event: QFocusEvent):
                print("Focus lost from the AA QLineEdit")
                print("QFocusEvent: ", QFocusEvent.reason(event))
                if self.hasAcceptableInput():
                    print("Input mask is valid")
                    super().focusOutEvent(event) # Added to make the cursor stop blinking after focus out
                else:
                    print("Input mask is invalid")
                    super().setFocus() # Set focus back to the line edit if input is invalid
                
    class CustomLineEdit2(QLineEdit):
            def __init__(self, parent=None):
               super().__init__(parent)
    
            def focusOutEvent(self, event: QFocusEvent):
                print("Focus lost from the BB QLineEdit")
                print("QFocusEvent: ", QFocusEvent.reason(event))
                if self.hasAcceptableInput():
                    print("Input mask is valid")
                    super().focusOutEvent(event)  # Added to make the cursor stop blinking after focus out
                else:
                    print("Input mask is invalid")
                    super().setFocus() # Set focus back to the line edit if input is invalid
    
    def on_text_changed1(self):
        print("Text changed:", self.line_edit1.text())
        if len(self.line_edit1.text()) == 9:
            print("Validate:", self.line_edit1.hasAcceptableInput())
            print("Input mask completed for AA Box.")
            self.line_edit1.isEnabled = True
            self.line_edit1.setFocus()
        else:
            print("Validate:", self.line_edit1.hasAcceptableInput())
            print("Input mask not completed for AA Box.")
    
    def on_text_changed2(self):
        print("Text changed:", self.line_edit2.text())
        if len(self.line_edit2.text()) == 8:
            print("Validate:", self.line_edit2.hasAcceptableInput())
            print("Input mask completed for BB Box.")
    
        else:
            print("Validate:", self.line_edit2.hasAcceptableInput())
            print("Input mask not completed for BB Box.")
    
    class MyWindow(QWidget):
        def __init__(self):
            super().__init__()
    
            self.line_edit1 = CustomLineEdit1()
            self.line_edit1.setInputMask('>AA999-99A')   #AA Box
            self.line_edit1.textChanged.connect(lambda: on_text_changed1(self))
            self.line_edit1.editingFinished
    
            self.line_edit2 = CustomLineEdit2()
            self.line_edit2.setInputMask('>AAAA-99A')  # BB Box
            self.line_edit2.textChanged.connect(lambda: on_text_changed2(self)) 
            self.line_edit2.isEnabled = False     
            
            self.line_edit3 = QLineEdit() 
    
            layout = QVBoxLayout()
            layout.addWidget(self.line_edit1)
            # layout.addWidget(self.line_edit3)  # Put line_edit3 here and everything works fine
            layout.addWidget(self.line_edit2)
            layout.addWidget(self.line_edit3) # Put line_edit3 here and it breaks the code
            
            self.setLayout(layout)
    
    if __name__ == '__main__':
        app = QApplication([])
        window = MyWindow()
        window.show()
        app.exec()
    
    J 1 Reply Last reply 22 Apr 2025, 12:27
    0
    • B BretO
      22 Apr 2025, 12:20

      I'm working on a PYQT app and have two lineEdit boxes (line_edit1 and line_edit2) with input masks. Since editingFinished only triggers if the input mask is complete it looks like I need to create a custom focusOutEvent to be able to check if the user leaves the box before they complete the full input mask and set the focus back in that lineEdit. The problem is it seems the focusOutEvent is getting stuck in a loop if I have both custom lineEdits right after each other. If I put a normal lineEdit (line_edit3) between 1 and 2 then everything works as expected.

      In watching the debug with line_edit1 and 2 together when I enter the first character in line_edit1 it goes to my on_text_changed1 function and evaluates if it has the correct number of characters and prints out the status. It then immediately goes to the custom focusOutEvent for line_edit1 and checks. (Not sure why since this should only be checking for the text changed and not a focus out) and then goes to line_edit2 and checks it's focusOutEvent and back to line_edit1 again and into a loop until it crashes.

      If I have line_edit3 in between 1 and 2 then it does not bounce back and forth between the focusOutEvent of 1 and 2.

      Maybe I have not done the custom focusOutEvent correctly?
      Any help would be appreciated.

      from PyQt6.QtWidgets import QApplication, QLineEdit, QWidget, QVBoxLayout
      from PyQt6.QtGui import QFocusEvent
      
      class CustomLineEdit1(QLineEdit):
              def __init__(self, parent=None):
                 super().__init__(parent)
      
              def focusOutEvent(self, event: QFocusEvent):
                  print("Focus lost from the AA QLineEdit")
                  print("QFocusEvent: ", QFocusEvent.reason(event))
                  if self.hasAcceptableInput():
                      print("Input mask is valid")
                      super().focusOutEvent(event) # Added to make the cursor stop blinking after focus out
                  else:
                      print("Input mask is invalid")
                      super().setFocus() # Set focus back to the line edit if input is invalid
                  
      class CustomLineEdit2(QLineEdit):
              def __init__(self, parent=None):
                 super().__init__(parent)
      
              def focusOutEvent(self, event: QFocusEvent):
                  print("Focus lost from the BB QLineEdit")
                  print("QFocusEvent: ", QFocusEvent.reason(event))
                  if self.hasAcceptableInput():
                      print("Input mask is valid")
                      super().focusOutEvent(event)  # Added to make the cursor stop blinking after focus out
                  else:
                      print("Input mask is invalid")
                      super().setFocus() # Set focus back to the line edit if input is invalid
      
      def on_text_changed1(self):
          print("Text changed:", self.line_edit1.text())
          if len(self.line_edit1.text()) == 9:
              print("Validate:", self.line_edit1.hasAcceptableInput())
              print("Input mask completed for AA Box.")
              self.line_edit1.isEnabled = True
              self.line_edit1.setFocus()
          else:
              print("Validate:", self.line_edit1.hasAcceptableInput())
              print("Input mask not completed for AA Box.")
      
      def on_text_changed2(self):
          print("Text changed:", self.line_edit2.text())
          if len(self.line_edit2.text()) == 8:
              print("Validate:", self.line_edit2.hasAcceptableInput())
              print("Input mask completed for BB Box.")
      
          else:
              print("Validate:", self.line_edit2.hasAcceptableInput())
              print("Input mask not completed for BB Box.")
      
      class MyWindow(QWidget):
          def __init__(self):
              super().__init__()
      
              self.line_edit1 = CustomLineEdit1()
              self.line_edit1.setInputMask('>AA999-99A')   #AA Box
              self.line_edit1.textChanged.connect(lambda: on_text_changed1(self))
              self.line_edit1.editingFinished
      
              self.line_edit2 = CustomLineEdit2()
              self.line_edit2.setInputMask('>AAAA-99A')  # BB Box
              self.line_edit2.textChanged.connect(lambda: on_text_changed2(self)) 
              self.line_edit2.isEnabled = False     
              
              self.line_edit3 = QLineEdit() 
      
              layout = QVBoxLayout()
              layout.addWidget(self.line_edit1)
              # layout.addWidget(self.line_edit3)  # Put line_edit3 here and everything works fine
              layout.addWidget(self.line_edit2)
              layout.addWidget(self.line_edit3) # Put line_edit3 here and it breaks the code
              
              self.setLayout(layout)
      
      if __name__ == '__main__':
          app = QApplication([])
          window = MyWindow()
          window.show()
          app.exec()
      
      J Offline
      J Offline
      jsulm
      Lifetime Qt Champion
      wrote on 22 Apr 2025, 12:27 last edited by
      #2

      @BretO Maybe you should https://doc.qt.io/qt-6/qevent.html#accept the event in the "else" part?

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      B 1 Reply Last reply 22 Apr 2025, 12:49
      0
      • J jsulm
        22 Apr 2025, 12:27

        @BretO Maybe you should https://doc.qt.io/qt-6/qevent.html#accept the event in the "else" part?

        B Offline
        B Offline
        BretO
        wrote on 22 Apr 2025, 12:49 last edited by
        #3

        @jsulm Which else are you referring to?
        I looked at that link but I'm not sure how I would put that in.

        I'm still pretty new to QT so trying to understand the documentation is not always easy.

        J J 2 Replies Last reply 22 Apr 2025, 13:04
        0
        • B BretO
          22 Apr 2025, 12:49

          @jsulm Which else are you referring to?
          I looked at that link but I'm not sure how I would put that in.

          I'm still pretty new to QT so trying to understand the documentation is not always easy.

          J Offline
          J Offline
          jsulm
          Lifetime Qt Champion
          wrote on 22 Apr 2025, 13:04 last edited by jsulm
          #4

          @BretO said in FocusOutEvent get stuck in a loop:

          Which else are you referring to?

          def focusOutEvent(self, event: QFocusEvent):
                      print("Focus lost from the AA QLineEdit")
                      print("QFocusEvent: ", QFocusEvent.reason(event))
                      if self.hasAcceptableInput():
                          print("Input mask is valid")
                          super().focusOutEvent(event) # Added to make the cursor stop blinking after focus out
                      else:
                         # HERE
                          print("Input mask is invalid")
                          super().setFocus()
                          event.accept()
          

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • B BretO
            22 Apr 2025, 12:49

            @jsulm Which else are you referring to?
            I looked at that link but I'm not sure how I would put that in.

            I'm still pretty new to QT so trying to understand the documentation is not always easy.

            J Offline
            J Offline
            JonB
            wrote on 22 Apr 2025, 13:05 last edited by
            #5

            @BretO
            The else in the event, your focusOutEvent(). Try putting in event.accept() in the only else clause there, perhaps just before the setFocus(). I don't know whether that will help, but it's @jsulm's idea to prevent further propagation of that event.

            1 Reply Last reply
            0
            • B Offline
              B Offline
              BretO
              wrote on 22 Apr 2025, 13:09 last edited by
              #6

              OK. I just tried putting it before and after the super().setFocus() on both focusoutevents with the same results of it getting stuck in the loop.

              1 Reply Last reply
              0
              • B Offline
                B Offline
                BretO
                wrote on 22 Apr 2025, 18:00 last edited by
                #7

                I've been digging through this some more and what appears to be happening is when I press tab to leave line_edit1 it goes to my focusOutEvent of CustomLineEdit1 and sets the focus back to line_edit1 but it is like the focus has also transferred over to line_edit2 so when the super().setfocus of line_edit1 happens then line_edit2 sees that and fires off it's focusOutEvent and this keeps going back and forth since they each see the focus leaving their respective line edits.

                If I remove the super().setfocus from the else of line_edit2 things work because there is nothing telling it to take the focus back away from line_edit1. The problem with this is that after I do go on to line_edit2 and tab out of it to go to line_edit3, with out the super().setfocus in the else the focus does not return to line_edit2 like I need it to.

                The event.accept() have had no effect.

                Unless there is something else going on here it seems like the focus should never make it to line_edit2 if I'm intercepting the focusOutEvent of line_edit1 and changing it.

                1 Reply Last reply
                0

                7/7

                22 Apr 2025, 18:00

                • Login

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