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. Modified mousePressEvent() function applied to top level widgets running multiple times per click
Forum Update on Monday, May 27th 2025

Modified mousePressEvent() function applied to top level widgets running multiple times per click

Scheduled Pinned Locked Moved Solved Qt for Python
qt for pythonpyside2
3 Posts 2 Posters 2.0k 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.
  • H Offline
    H Offline
    Hyperdimensional
    wrote on last edited by Hyperdimensional
    #1

    Hello all,

    I’m new to Python, Qt, and programming in general.

    I am working on a module that involves finding the top level widgets in a window and changing their mousePressEvent functions, so the module can be used without the user (probably just me) having to manually change the top level mousePressEvent functions. However, I do not want it to override any modified mousePressEvent if someone has modified the original for other purposes. As an example, if this is the top level widget that contains 3 instances of my widget ‘MyWidget’ from my module, with a custom mousePressEvent added:

    class WIND(QWidget):
        def __init__(self, parent=None):
            super(WIND, self).__init__(parent)
            self.layout = QVBoxLayout()
            self.setLayout(self.layout)
            self.someWidget1 = MyWidget()
            self.someWidget2 = MyWidget()
            self.someWidget3 = MyWidget()
            self.layout.addWidget(self.someWidget1)
            self.layout.addWidget(self.someWidget2)
            self.layout.addWidget(self.someWidget3)
    
        def mousePressEvent(self, event): #I DON’T want this to be overwritten if someone (probably just me) uses my module
            super(WIND, self).mousePressEvent(event)
            print(“Modified mousePressEvent has been triggered”)
    

    Within MyWidget (a child of another class in the module, see my next post below) in the module, I find the top-level widgets with

    top_widgets = QApplication.topLevelWidgets()
    

    I then iterate through them, replacing their mousePressEvent with ‘newMousePressEvent’ from within my module:

    for tw in top_widgets:
                original_MPE = tw.mousePressEvent 
                MPE = partial(self.newMousePressEvent, tw, original_MPE)
                tw.mousePressEvent = MPE
    

    And here’s the function referenced in the partial function above, to act as the top level widget's mousePressEvent function while still triggering the other mousePressEvent:

    def newMousePressEvent(self, top_widget, original_mousePressEvent, event):
        """Overrides a class's mouse press event while still triggering the original mouse press event"""
        print(top_widget) 
        original_mousePressEvent(event)
    
        #do stuff here
    

    At least in my limited test, this code does work, activating both the modified WIND.mousePressEvent and the MyWidget.newMousePressEvent function. However, when I run the program and click somewhere in the window, the print lines reveal that the function does successfully run the modified WIND.mousePressEvent function once, but also runs the print(top_widget) line 3 times per click, outputting the exact same Widget object (WIND), corresponding to the 3 instances of MyWidget within WIND (the number of prints changed depending on how many instances I put in). This is what it prints:

    <__main__.WIND object at 0x7ff0687c2230>
    <__main__.WIND object at 0x7ff0687c2230>
    <__main__.WIND object at 0x7ff0687c2230>
    Modified mousePressEvent has been triggered
    

    Essentially, I technically got this to work, but I’m not sure why it’s running certain things in the newMousePressEvent function multiple times (except for the original_mousePressEvent function??). It would be great to get the function to only run once for the topmost widget.

    Instead of doing this, I also tried putting super(type(parent), parent).mousePressEvent(event) within the newMousePressEvent function, but this did not trigger the modified WIND mousePressEvent function.

    Thank you for any input into what is happening!

    1 Reply Last reply
    0
    • H Offline
      H Offline
      Hyperdimensional
      wrote on last edited by
      #2

      Sorry, I was trying to make it as simple as possible for the sake of responders. Ironically, I left out one part that now seems to me to be relevant to the issue: the fact that 'MyWidget' is a child of a parent 'ClickEdit'. I'm using inheritance because each child will be for handling how different built in QWidgets, such as QSpinBox, QTimeEdit, etc., respond to clicks within the window:

      class MyWidget(ClickEdit):
          #I have multiple widgets as children of ClickEdit, each for a different QWidget class
          def __init__(self):
              ClickEdit.__init__(self, QSpinBox, parent=None)
      

      Here's the entire code, hopefully as bare bones as possible:

      import sys
      from functools import partial
      from PySide2.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout, QVBoxLayout, QSpinBox
      
      class WIND(QWidget):
          def __init__(self, parent=None):
              super(WIND, self).__init__(parent)
              self.layout = QVBoxLayout()
              self.setLayout(self.layout)
              self.number = MyWidget()
              self.number2 = MyWidget()
              self.number3 = MyWidget()
      
              self.layout.addWidget(self.number)
              self.layout.addWidget(self.number2)
              self.layout.addWidget(self.number3)
      
          def mousePressEvent(self, event):
              super(WIND, self).mousePressEvent(event)
              print("Modified mousePressEvent has been triggered")
      
      class ClickEdit(QWidget):
          def __init__(self, type_of_edit_field, parent=None):
              super(ClickEdit, self).__init__(parent)
              self.QWidgettype = type_of_edit_field
              self.layout = QHBoxLayout()
              self.setLayout(self.layout)
      
              top_widgets = QApplication.topLevelWidgets()
              
              self.layout.addWidget(self.QWidgettype())
              
              for tw in top_widgets:
                  original_MPE = tw.mousePressEvent 
                  MPE = partial(self.newMousePressEvent, tw, original_MPE)
                  tw.mousePressEvent = MPE
      
          def newMousePressEvent(self, top_widget, original_mousePressEvent, event):
              """Overrides a class's mouse press event while still triggering the original mouse press event"""
              print(top_widget) 
              original_mousePressEvent(event)
      
              #do stuff here: if the click is within the window but outside of the bounds of self.QWidgettype, self.QWidgettype will be changed.
      
      class MyWidget(ClickEdit):
          #I have multiple widgets as children of ClickEdit, each for a different QWidget class
          def __init__(self):
              ClickEdit.__init__(self, QSpinBox, parent=None)
      
      if __name__ == '__main__':
      
          app = QApplication(sys.argv)
      
          window = WIND()
          window.show()
      
          sys.exit(app.exec_())
      
      1 Reply Last reply
      0
      • H Offline
        H Offline
        Hyperdimensional
        wrote on last edited by
        #3

        I figured it out. It was something I definitely should have realized.

        Since I changed the top widget mouse press events in the init function of the ClickEdit class, it was assigning new mouse press events to the same top level widget again and again for every instance of ClickEdit in the window. I'm still ignorant of the mechanics of why it runs multiple times from being reassigned more than once, but I at least fixed the issue by creating a list called top_widgets_modified shared between all ClickEdit instances that consists of any top widgets already assigned a new mousePressEvent. If a top level widget has already been assigned a new mouse press event, it skips it in the next ClickEdit init.

        Alternatively, It might work to have it iterate through the top widgets once per window instead of for every ClickEdit init, though I'll have to make sure it won't miss anything by doing this.

        class ClickEdit(QWidget):
            top_widgets_modified = []
            
            def __init__(self, type_of_edit_field, parent=None):
                super(ClickEdit, self).__init__(parent)
                self.QWidgettype = type_of_edit_field
                self.layout = QHBoxLayout()
                self.setLayout(self.layout)
        
                top_widgets = QApplication.topLevelWidgets()
                
                self.layout.addWidget(self.QWidgettype())
        
                for tw in top_widgets:
                    if tw in self.top_widgets_modified:
                         continue
                    self.top_widgets_modified.append(tw)
                    
                    original_MPE = tw.mousePressEvent 
                    MPE = partial(self.newMousePressEvent, tw, original_MPE)
                    tw.mousePressEvent = MPE
        
        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