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. Catching child widget keyPressEvents
Forum Updated to NodeBB v4.3 + New Features

Catching child widget keyPressEvents

Scheduled Pinned Locked Moved Unsolved Qt for Python
9 Posts 2 Posters 1.3k 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.
  • F Offline
    F Offline
    fvez_demtroys
    wrote on last edited by
    #1

    Hi,

    We are making an internal configuration tool using PyQt5 5.15.4.
    Development is done on macOS Catalina 10.15.7
    The final version will run on both OSX and Windows 10

    I have a custom widget containing a QLineEdit.
    I would like to catch the QLineEdit's KeyPressEvents without having to make a custom QLineEdit class.

    Here is what I have done so far.
    In my custom widget class I override keyPressEvent. I then redirect the QLineEdit keyPressEvent to the one I wrote in the parent widget.

    class CustomWidget(QWidget):
        def __init__(self, parent):
            super(QWidget, self).__init__(parent)
    
        def keyPressEvent(self, event, widget=None, widgetType=None):
            if event.key() == Qt.Key_Return:
                self.returnKeyPressEventHandler()
                return
            if widget is None or widgetType is None:
                super(TerminalWidget, self).keyPressEvent(event)
            else:
                super(widgetType, widget).keyPressEvent(event)
    
        def initKeyPressEvents(self):
            self.lineEdit.keyPressEvent = lambda event: self.keyPressEvent(event, widget=self.lineEdit, widgetType=QLineEdit)
    

    This seems to redirect the keyPressEvent from the QLineEdit to the one I wrote in the parent class without issues.
    However, the line

            else:
                super(widgetType, widget).keyPressEvent(event)
    

    does not work. I want to only catch some specific key presses, if the key pressed is not the return key, I want the QLineEdit to behave normally.
    I thought the way to achieve this would be with "super".

    Is there a way to achieve what I want? I just want to catch keyPressEvents from the custom widget's children without having to make custom classes for each child.

    Thanks,
    FVez

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

      Hi,

      You should rather use an event filter as described in the QObject::installEventFilter.

      Out of curiosity, what other keys beside enter do you want to catch ?

      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
      • F Offline
        F Offline
        fvez_demtroys
        wrote on last edited by
        #3

        Hi SGaist,

        I'll have a look at the installEventFilter, it does seem to be what I am looking for.
        A couple different presses, mostly the return key and some copy paste shortcuts for our custom tables.

        Thanks, I'll post here again if I can't get the installEventFilter to work.

        FVez

        1 Reply Last reply
        0
        • F Offline
          F Offline
          fvez_demtroys
          wrote on last edited by
          #4

          Hi SGaist,

          So I'm having some issues implementing the installEventFilter.
          Here is my custom filter class :

          
          class KeyPressEventHandler(QObject):
              def __init__(self,
                           # No modifier key
                           returnKeyPressEventHandler=None, upKeyPressEventHandler=None, 
                           downKeyPressEventHandler=None, deleteKeyPressEventHandler=None,
                           # Control and Shift modifier keys
                           controlShiftZKeyPressEventHandler=None,
                           # Shift modifier key
                           shiftReturnKeyPressEventHandler=None,
                           # Control modifier key
                           controlFKeyPressEventHandler=None, controlZKeyPressEventHandler=None, 
                           controlCKeyPressEventHandler=None,
                           controlXKeyPressEventHandler=None, controlVKeyPressEventHandler=None, 
                           controlBackspaceKeyPressEventHandler=None):
                  super().__init__()
                  # No modifier key
                  self.returnKeyPressEventHandler = returnKeyPressEventHandler
                  self.upKeyPressEventHandler = upKeyPressEventHandler
                  self.downKeyPressEventHandler = downKeyPressEventHandler
                  self.deleteKeyPressEventHandler = deleteKeyPressEventHandler
                  # Control and Shift modifier keys
                  self.controlShiftZKeyPressEventHandler = controlShiftZKeyPressEventHandler
                  # Shift modifier key
                  self.shiftReturnKeyPressEventHandler = shiftReturnKeyPressEventHandler
                  # Control modifier key
                  self.controlFKeyPressEventHandler = controlFKeyPressEventHandler
                  self.controlZKeyPressEventHandler = controlZKeyPressEventHandler
                  self.controlCKeyPressEventHandler = controlCKeyPressEventHandler
                  self.controlXKeyPressEventHandler = controlXKeyPressEventHandler
                  self.controlVKeyPressEventHandler = controlVKeyPressEventHandler
                  self.controlBackspaceKeyPressEventHandler = controlBackspaceKeyPressEventHandler
          
              def keyPressEventHandler(self, obj, event):
                  print('keyPressEventHandler')
                  if event.type() == QEvent.KeyPress:
                      # Control and Shift modifier keys
                      if event.modifiers() & Qt.ControlModifier:
                          if event.modifiers() & Qt.ShiftModifier:
                              if event.key() == Qt.Key_Z:
                                  self.controlShiftZKeyPressEventHandler()
                                  return True
                      # Shift modifier key
                      if event.modifiers() & Qt.ShiftModifier:
                          if event.key() == Qt.Key_Return:
                              if self.shiftReturnKeyPressEventHandler is not None:
                                  self.shiftReturnKeyPressEventHandler()
                                  return True
                      # Control modifier key
                      if event.modifiers() & Qt.ControlModifier:
                          if event.key() == Qt.Key_F:
                              if self.controlFKeyPressEventHandler is not None:
                                  self.controlFKeyPressEventHandler()
                                  return True
                          elif event.key() == Qt.Key_Z:
                              if self.controlZKeyPressEventHandler is not None:
                                  self.controlZKeyPressEventHandler()
                                  return True
                          elif event.key() == Qt.Key_C:
                              if self.controlCKeyPressEventHandler is not None:
                                  self.controlCKeyPressEventHandler()
                                  return True
                          elif event.key() == Qt.Key_X:
                              if self.controlXKeyPressEventHandler is not None:
                                  self.controlXKeyPressEventHandler()
                                  return True
                          elif event.key() == Qt.Key_V:
                              if self.controlVKeyPressEventHandler is not None:
                                  self.controlVKeyPressEventHandler()
                                  return True
                          elif event.key() == Qt.Key_Backspace:
                              if self.controlBackspaceKeyPressEventHandler is not None:
                                  self.controlBackspaceKeyPressEventHandler()
                                  return True
                      # No modifier key
                      if event.key() == Qt.Key_Return:
                          if self.returnKeyPressEventHandler is not None:
                              self.returnKeyPressEventHandler()
                              return True
                      elif event.key() == Qt.Key_Up:
                          if self.upKeyPressEventHandler is not None:
                              self.upKeyPressEventHandler()
                              return True
                      elif event.key() == Qt.Key_Down:
                          if self.downKeyPressEventHandler is not None:
                              self.downKeyPressEventHandler()
                              return True
                      elif event.key() == Qt.Key_Delete:
                          if self.deleteKeyPressEventHandler is not None:
                              self.deleteKeyPressEventHandler()
                              return True
          
                  return QObject.eventFilter(obj, event)
          

          And here is how I've implemented it in my terminal class :

          class TerminalWidget(QWidget):
          
              def __init__(self, main, mainWindow, parent):
                  super(QWidget, self).__init__(parent)
                  self.main = main
                  self.mainWindow = mainWindow
                  self.parent = parent
                  self.osName = self.main.osName
          
                  self.terminalSearch = TerminalSearch(self, self.mainWindow)
          
                  self.initWidget()
                  self.initCriticalWidgets()
          
              def initKeyPressEventHandler(self):
                  self.lineEdit_terminalSearch_keyPressEventHandler = KeyPressEventHandler(self,
                                                                                           returnKeyPressEventHandler=self.terminalSearch.search,
                                                                                           upKeyPressEventHandler=self.terminalSearch.iterateUp,
                                                                                           downKeyPressEventHandler=self.terminalSearch.iterateDown,
                                                                                           shiftReturnKeyPressEventHandler=self.terminalSearch.iterateUp,
                                                                                           controlFKeyPressEventHandler=self.lineEdit_terminalSearch.selectAll)
                  self.lineEdit_terminalSearch.installEventFilter(self.lineEdit_terminalSearch_keyPressEventHandler)
          
                  self.textEdit_terminal_keyPressEventHandler = KeyPressEventHandler(self, controlFKeyPressEventHandler=self.textEdit_terminal_controlFKeyPressEventHandler)
                  self.textEdit_terminal.installEventFilter(self.textEdit_terminal_keyPressEventHandler)
          
                  self.lineEdit_terminal_keyPressEventHandler = KeyPressEventHandler(self,
                                                                                     returnKeyPressEventHandler=self.pushButton_send_terminal.animateClick,
                                                                                     upKeyPressEventHandler=self.main.terminalCommandHistory.getPreviousCommand,
                                                                                     downKeyPressEventHandler=self.main.terminalCommandHistory.getNextCommand,
                                                                                     controlFKeyPressEventHandler=self.lineEdit_terminal_controlFKeyPressEventHandler)
                  self.lineEdit_terminal.installEventFilter(self.lineEdit_terminal_keyPressEventHandler)
          

          I have one KeyPressEventHandler class for every widget from which I want to catch the key presses. I then pass the functions to call directly to the class init call.

          I am having some issues with the implementation. Here is my first problem.
          When I run the application, I get the following error.

          self.lineEdit_terminalSearch_keyPressEventHandler = KeyPressEventHandler(self,
          TypeError: __init__() got multiple values for argument 'returnKeyPressEventHandler'
          

          I am not sure why I get the TypeError since I am apassing a single function to the init call...
          Could you help with this? Do you see why it sees "multiple values" for the returnKeyPressEventHandler argument?

          Thanks!
          FVez

          F 1 Reply Last reply
          0
          • F fvez_demtroys

            Hi SGaist,

            So I'm having some issues implementing the installEventFilter.
            Here is my custom filter class :

            
            class KeyPressEventHandler(QObject):
                def __init__(self,
                             # No modifier key
                             returnKeyPressEventHandler=None, upKeyPressEventHandler=None, 
                             downKeyPressEventHandler=None, deleteKeyPressEventHandler=None,
                             # Control and Shift modifier keys
                             controlShiftZKeyPressEventHandler=None,
                             # Shift modifier key
                             shiftReturnKeyPressEventHandler=None,
                             # Control modifier key
                             controlFKeyPressEventHandler=None, controlZKeyPressEventHandler=None, 
                             controlCKeyPressEventHandler=None,
                             controlXKeyPressEventHandler=None, controlVKeyPressEventHandler=None, 
                             controlBackspaceKeyPressEventHandler=None):
                    super().__init__()
                    # No modifier key
                    self.returnKeyPressEventHandler = returnKeyPressEventHandler
                    self.upKeyPressEventHandler = upKeyPressEventHandler
                    self.downKeyPressEventHandler = downKeyPressEventHandler
                    self.deleteKeyPressEventHandler = deleteKeyPressEventHandler
                    # Control and Shift modifier keys
                    self.controlShiftZKeyPressEventHandler = controlShiftZKeyPressEventHandler
                    # Shift modifier key
                    self.shiftReturnKeyPressEventHandler = shiftReturnKeyPressEventHandler
                    # Control modifier key
                    self.controlFKeyPressEventHandler = controlFKeyPressEventHandler
                    self.controlZKeyPressEventHandler = controlZKeyPressEventHandler
                    self.controlCKeyPressEventHandler = controlCKeyPressEventHandler
                    self.controlXKeyPressEventHandler = controlXKeyPressEventHandler
                    self.controlVKeyPressEventHandler = controlVKeyPressEventHandler
                    self.controlBackspaceKeyPressEventHandler = controlBackspaceKeyPressEventHandler
            
                def keyPressEventHandler(self, obj, event):
                    print('keyPressEventHandler')
                    if event.type() == QEvent.KeyPress:
                        # Control and Shift modifier keys
                        if event.modifiers() & Qt.ControlModifier:
                            if event.modifiers() & Qt.ShiftModifier:
                                if event.key() == Qt.Key_Z:
                                    self.controlShiftZKeyPressEventHandler()
                                    return True
                        # Shift modifier key
                        if event.modifiers() & Qt.ShiftModifier:
                            if event.key() == Qt.Key_Return:
                                if self.shiftReturnKeyPressEventHandler is not None:
                                    self.shiftReturnKeyPressEventHandler()
                                    return True
                        # Control modifier key
                        if event.modifiers() & Qt.ControlModifier:
                            if event.key() == Qt.Key_F:
                                if self.controlFKeyPressEventHandler is not None:
                                    self.controlFKeyPressEventHandler()
                                    return True
                            elif event.key() == Qt.Key_Z:
                                if self.controlZKeyPressEventHandler is not None:
                                    self.controlZKeyPressEventHandler()
                                    return True
                            elif event.key() == Qt.Key_C:
                                if self.controlCKeyPressEventHandler is not None:
                                    self.controlCKeyPressEventHandler()
                                    return True
                            elif event.key() == Qt.Key_X:
                                if self.controlXKeyPressEventHandler is not None:
                                    self.controlXKeyPressEventHandler()
                                    return True
                            elif event.key() == Qt.Key_V:
                                if self.controlVKeyPressEventHandler is not None:
                                    self.controlVKeyPressEventHandler()
                                    return True
                            elif event.key() == Qt.Key_Backspace:
                                if self.controlBackspaceKeyPressEventHandler is not None:
                                    self.controlBackspaceKeyPressEventHandler()
                                    return True
                        # No modifier key
                        if event.key() == Qt.Key_Return:
                            if self.returnKeyPressEventHandler is not None:
                                self.returnKeyPressEventHandler()
                                return True
                        elif event.key() == Qt.Key_Up:
                            if self.upKeyPressEventHandler is not None:
                                self.upKeyPressEventHandler()
                                return True
                        elif event.key() == Qt.Key_Down:
                            if self.downKeyPressEventHandler is not None:
                                self.downKeyPressEventHandler()
                                return True
                        elif event.key() == Qt.Key_Delete:
                            if self.deleteKeyPressEventHandler is not None:
                                self.deleteKeyPressEventHandler()
                                return True
            
                    return QObject.eventFilter(obj, event)
            

            And here is how I've implemented it in my terminal class :

            class TerminalWidget(QWidget):
            
                def __init__(self, main, mainWindow, parent):
                    super(QWidget, self).__init__(parent)
                    self.main = main
                    self.mainWindow = mainWindow
                    self.parent = parent
                    self.osName = self.main.osName
            
                    self.terminalSearch = TerminalSearch(self, self.mainWindow)
            
                    self.initWidget()
                    self.initCriticalWidgets()
            
                def initKeyPressEventHandler(self):
                    self.lineEdit_terminalSearch_keyPressEventHandler = KeyPressEventHandler(self,
                                                                                             returnKeyPressEventHandler=self.terminalSearch.search,
                                                                                             upKeyPressEventHandler=self.terminalSearch.iterateUp,
                                                                                             downKeyPressEventHandler=self.terminalSearch.iterateDown,
                                                                                             shiftReturnKeyPressEventHandler=self.terminalSearch.iterateUp,
                                                                                             controlFKeyPressEventHandler=self.lineEdit_terminalSearch.selectAll)
                    self.lineEdit_terminalSearch.installEventFilter(self.lineEdit_terminalSearch_keyPressEventHandler)
            
                    self.textEdit_terminal_keyPressEventHandler = KeyPressEventHandler(self, controlFKeyPressEventHandler=self.textEdit_terminal_controlFKeyPressEventHandler)
                    self.textEdit_terminal.installEventFilter(self.textEdit_terminal_keyPressEventHandler)
            
                    self.lineEdit_terminal_keyPressEventHandler = KeyPressEventHandler(self,
                                                                                       returnKeyPressEventHandler=self.pushButton_send_terminal.animateClick,
                                                                                       upKeyPressEventHandler=self.main.terminalCommandHistory.getPreviousCommand,
                                                                                       downKeyPressEventHandler=self.main.terminalCommandHistory.getNextCommand,
                                                                                       controlFKeyPressEventHandler=self.lineEdit_terminal_controlFKeyPressEventHandler)
                    self.lineEdit_terminal.installEventFilter(self.lineEdit_terminal_keyPressEventHandler)
            

            I have one KeyPressEventHandler class for every widget from which I want to catch the key presses. I then pass the functions to call directly to the class init call.

            I am having some issues with the implementation. Here is my first problem.
            When I run the application, I get the following error.

            self.lineEdit_terminalSearch_keyPressEventHandler = KeyPressEventHandler(self,
            TypeError: __init__() got multiple values for argument 'returnKeyPressEventHandler'
            

            I am not sure why I get the TypeError since I am apassing a single function to the init call...
            Could you help with this? Do you see why it sees "multiple values" for the returnKeyPressEventHandler argument?

            Thanks!
            FVez

            F Offline
            F Offline
            fvez_demtroys
            wrote on last edited by
            #5

            @SGaist
            Sorry for tagging you, I forgot to mark the post as a direct reply to your comment.

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

              Short version of your class:

              class KeyPressEventHandler(QObject):
                  def __init__(self,
                               # No modifier key
                               returnKeyPressEventHandler=None,
                               # etc.
              

              Instanciation code:

              self.lineEdit_terminalSearch_keyPressEventHandler = KeyPressEventHandler(self,
                                                                                               returnKeyPressEventHandler=self.terminalSearch.search,
              

              The first parameter you pass is self, which is going to go into the first parameter of the init function which is returnKeyPressEventHandler and then you explicitly set returnKeyPressEventHandler hence your error.

              The self parameter of class member functions is not a parameter you pass when calling the method.

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

              F 1 Reply Last reply
              0
              • F Offline
                F Offline
                fvez_demtroys
                wrote on last edited by
                #7

                Hi SGaist,

                So by removing self in the init calls
                FROM

                        self.lineEdit_terminalSearch_keyPressEventHandler = KeyPressEventHandler(self,
                                                                                                 returnKeyPressEventHandler=self.terminalSearch.search,
                                                                                                 upKeyPressEventHandler=self.terminalSearch.iterateUp,
                                                                                                 downKeyPressEventHandler=self.terminalSearch.iterateDown,
                                                                                                 shiftReturnKeyPressEventHandler=self.terminalSearch.iterateUp,
                                                                                                 controlFKeyPressEventHandler=self.lineEdit_terminalSearch.selectAll)
                

                TO

                        self.lineEdit_terminalSearch_keyPressEventHandler = KeyPressEventHandler(returnKeyPressEventHandler=self.terminalSearch.search,
                                                                                                 upKeyPressEventHandler=self.terminalSearch.iterateUp,
                                                                                                 downKeyPressEventHandler=self.terminalSearch.iterateDown,
                                                                                                 shiftReturnKeyPressEventHandler=self.terminalSearch.iterateUp,
                                                                                                 controlFKeyPressEventHandler=self.lineEdit_terminalSearch.selectAll)
                

                It fixed my multiple values for argument problem. I thought I was always supposed to pass self in the class init but it seems like I was mistaken.

                1 Reply Last reply
                0
                • SGaistS SGaist

                  Short version of your class:

                  class KeyPressEventHandler(QObject):
                      def __init__(self,
                                   # No modifier key
                                   returnKeyPressEventHandler=None,
                                   # etc.
                  

                  Instanciation code:

                  self.lineEdit_terminalSearch_keyPressEventHandler = KeyPressEventHandler(self,
                                                                                                   returnKeyPressEventHandler=self.terminalSearch.search,
                  

                  The first parameter you pass is self, which is going to go into the first parameter of the init function which is returnKeyPressEventHandler and then you explicitly set returnKeyPressEventHandler hence your error.

                  The self parameter of class member functions is not a parameter you pass when calling the method.

                  F Offline
                  F Offline
                  fvez_demtroys
                  wrote on last edited by
                  #8

                  @SGaist
                  I see!

                  Big thanks!
                  FVez

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

                    No, "self" is a reference to the object itself. This allows you to call other functions of the object, use member variables, etc.

                    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

                    • Login

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