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. How to make QPainter elements clickable-through using PyQt
Forum Updated to NodeBB v4.3 + New Features

How to make QPainter elements clickable-through using PyQt

Scheduled Pinned Locked Moved Unsolved Qt for Python
11 Posts 4 Posters 3.7k Views 2 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.
  • I Offline
    I Offline
    igonro
    wrote on last edited by
    #1

    I am trying to create a desktop application for Windows 10 using PyQt.

    The application will be an overlay, so it has to be transparent, clickable-through and always on top. An object detector will detect some regions of interest and a rectangle will be painted in that region.

    The overlay is almost fine. Right now it's able to draw random rectangles and while the background is transparent you can click through the background. The problem is that I can't click through the rectangles.

    I've tried the WA_TransparentForMouseEvents attribute, but it didn't work correctly. When I set this attribute the buttons stop working (I would expect this behaviour, and I don't care since the buttons are just for debuging), but I still can't click through the buttons or the rectangles.

    This is my code sample:

    import sys
    from PyQt6.QtCore import Qt
    from PyQt6.QtGui import QBrush, QColor, QPainter, QPen
    from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QStackedWidget
    import numpy as np
    
    
    class OverlayScreen(QMainWindow):
        def __init__(self):
            super().__init__()
            self.setFixedHeight(1080)
            self.setFixedWidth(1920)
            self.setObjectName("overlay")
            self.setStyleSheet("QMainWindow#overlay {background-color: rgba(0, 0, 0, 125)}")
            self.bg_transparent = False
    
            self.toggle_btn = QPushButton("Toggle", self)
            self.toggle_btn.setGeometry(200, 150, 100, 30)
            self.toggle_btn.clicked.connect(self.toggle_background)
            self.draw_btn = QPushButton("Draw rectangle", self)
            self.draw_btn.setGeometry(320, 150, 100, 30)
            self.draw_btn.clicked.connect(self.draw_rectangle)
            self.rectangles = []
    
            self.close_btn = QPushButton("Close", self)
            self.close_btn.setGeometry(200, 200, 100, 30)
            self.close_btn.clicked.connect(sys.exit)
    
        def toggle_background(self):
            self.bg_transparent = not self.bg_transparent
            if self.bg_transparent:
                self.setStyleSheet("QMainWindow#overlay {background-color: transparent}")
            else:
                self.setStyleSheet("QMainWindow#overlay {background-color: rgba(0, 0, 0, 125)}")
    
        def draw_rectangle(self):
            # self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents)
            rect = [np.random.randint(1920 - 150),
                    np.random.randint(1080 - 100),
                    np.random.randint(150),
                    np.random.randint(100)]
            self.rectangles.append(rect)
            self.update()
    
        def paintEvent(self, event):
            painter = QPainter(self)
            painter.setPen(QPen(Qt.GlobalColor.green, 1))
            painter.setBrush(QBrush(QColor(0, 255, 0, 80), Qt.BrushStyle.SolidPattern))
            for rect in self.rectangles:
                painter.drawRect(*rect)
            painter.end()
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        main = QStackedWidget()
        main.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        main.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
        main.move(0, 0)
        overlay = OverlayScreen()
        main.addWidget(overlay)
        main.show()
    
        try:
            sys.exit(app.exec())
        except Exception:
            print("Error")
    
    jeremy_kJ enjoysmathE 2 Replies Last reply
    1
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to devnet,

      Which version of PyQt are you using ?
      How did you install it ?

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

      I 1 Reply Last reply
      0
      • I igonro

        I am trying to create a desktop application for Windows 10 using PyQt.

        The application will be an overlay, so it has to be transparent, clickable-through and always on top. An object detector will detect some regions of interest and a rectangle will be painted in that region.

        The overlay is almost fine. Right now it's able to draw random rectangles and while the background is transparent you can click through the background. The problem is that I can't click through the rectangles.

        I've tried the WA_TransparentForMouseEvents attribute, but it didn't work correctly. When I set this attribute the buttons stop working (I would expect this behaviour, and I don't care since the buttons are just for debuging), but I still can't click through the buttons or the rectangles.

        This is my code sample:

        import sys
        from PyQt6.QtCore import Qt
        from PyQt6.QtGui import QBrush, QColor, QPainter, QPen
        from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QStackedWidget
        import numpy as np
        
        
        class OverlayScreen(QMainWindow):
            def __init__(self):
                super().__init__()
                self.setFixedHeight(1080)
                self.setFixedWidth(1920)
                self.setObjectName("overlay")
                self.setStyleSheet("QMainWindow#overlay {background-color: rgba(0, 0, 0, 125)}")
                self.bg_transparent = False
        
                self.toggle_btn = QPushButton("Toggle", self)
                self.toggle_btn.setGeometry(200, 150, 100, 30)
                self.toggle_btn.clicked.connect(self.toggle_background)
                self.draw_btn = QPushButton("Draw rectangle", self)
                self.draw_btn.setGeometry(320, 150, 100, 30)
                self.draw_btn.clicked.connect(self.draw_rectangle)
                self.rectangles = []
        
                self.close_btn = QPushButton("Close", self)
                self.close_btn.setGeometry(200, 200, 100, 30)
                self.close_btn.clicked.connect(sys.exit)
        
            def toggle_background(self):
                self.bg_transparent = not self.bg_transparent
                if self.bg_transparent:
                    self.setStyleSheet("QMainWindow#overlay {background-color: transparent}")
                else:
                    self.setStyleSheet("QMainWindow#overlay {background-color: rgba(0, 0, 0, 125)}")
        
            def draw_rectangle(self):
                # self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents)
                rect = [np.random.randint(1920 - 150),
                        np.random.randint(1080 - 100),
                        np.random.randint(150),
                        np.random.randint(100)]
                self.rectangles.append(rect)
                self.update()
        
            def paintEvent(self, event):
                painter = QPainter(self)
                painter.setPen(QPen(Qt.GlobalColor.green, 1))
                painter.setBrush(QBrush(QColor(0, 255, 0, 80), Qt.BrushStyle.SolidPattern))
                for rect in self.rectangles:
                    painter.drawRect(*rect)
                painter.end()
        
        
        if __name__ == "__main__":
            app = QApplication(sys.argv)
            main = QStackedWidget()
            main.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
            main.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
            main.move(0, 0)
            overlay = OverlayScreen()
            main.addWidget(overlay)
            main.show()
        
            try:
                sys.exit(app.exec())
            except Exception:
                print("Error")
        
        jeremy_kJ Online
        jeremy_kJ Online
        jeremy_k
        wrote on last edited by
        #3

        @igonro said in How to make QPainter elements clickable-through using PyQt:

        I am trying to create a desktop application for Windows 10 using PyQt.

        The application will be an overlay, so it has to be transparent, clickable-through and always on top. An object detector will detect some regions of interest and a rectangle will be painted in that region.

        The overlay is almost fine. Right now it's able to draw random rectangles and while the background is transparent you can click through the background. The problem is that I can't click through the rectangles.

        Running the example on macOS, clicks also don't pass through the transparent region. I'm surprised they do on Windows.

        I've tried the WA_TransparentForMouseEvents attribute, but it didn't work correctly. When I set this attribute the buttons stop working (I would expect this behaviour, and I don't care since the buttons are just for debuging), but I still can't click through the buttons or the rectangles.

        This is my code sample:

        if __name__ == "__main__":
            app = QApplication(sys.argv)
            main = QStackedWidget()
            main.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
            main.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
            main.move(0, 0)
            overlay = OverlayScreen()
            main.addWidget(overlay)
            main.show()
        

        Is there a reason to add the QMainWindow-based overlay to a QStackedWidget? I would guess that's the problem. Even though the overlay doesn't accept mouse input, the widget it is embedded in can, and the QWindow looks like a normal input accepting window to the OS.

        This works for me with macOS, as far as I understand the problem. The buttons and extraneous code have been removed for simplicity.

        import sys
        import random
        
        from PyQt5.QtCore import Qt
        from PyQt5.QtGui import QBrush, QColor, QPainter, QPen, QGuiApplication
        from PyQt5.QtWidgets import QApplication, QWidget
        
        
        class OverlayScreen(QWidget):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self.screen = QGuiApplication.screens()[0]
                self.setFixedHeight(self.screen.size().width())
                self.setFixedWidth(self.screen.size().height())
                self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents)
        
                self.rectangles = []
                self.draw_rectangle()
                self.draw_rectangle()
                self.draw_rectangle()
        
            def draw_rectangle(self):
                rect = [random.randint(151, self.screen.size().height() - 1),
                        random.randint(101, self.screen.size().width() - 1),
                        random.randint(1, 150),
                        random.randint(1, 100)]
                self.rectangles.append(rect)
                self.update()
        
            def paintEvent(self, event):
                super().paintEvent(event)
                painter = QPainter(self)
                painter.setPen(QPen(Qt.GlobalColor.green, 1))
                painter.setBrush(QBrush(QColor(0, 255, 0, 80), Qt.BrushStyle.SolidPattern))
                for rect in self.rectangles:
                    painter.drawRect(*rect)
                painter.end()
        
        
        if __name__ == "__main__":
            app = QApplication(sys.argv)
            overlay = OverlayScreen()
            overlay.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
            overlay.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint )
            # WindowTransparentForInput can be used instead of WA_TransparentForMouseEvents
            #overlay.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint | Qt.WindowTransparentForInput)
            overlay.show()
        
            try:
                sys.exit(app.exec())
            except Exception:
                print("Error")
        

        Asking a question about code? http://eel.is/iso-c++/testcase/

        I 1 Reply Last reply
        1
        • SGaistS SGaist

          Hi and welcome to devnet,

          Which version of PyQt are you using ?
          How did you install it ?

          I Offline
          I Offline
          igonro
          wrote on last edited by
          #4

          @SGaist I'm using PyQt6, I just installed with pip install pyqt6.

          1 Reply Last reply
          0
          • jeremy_kJ jeremy_k

            @igonro said in How to make QPainter elements clickable-through using PyQt:

            I am trying to create a desktop application for Windows 10 using PyQt.

            The application will be an overlay, so it has to be transparent, clickable-through and always on top. An object detector will detect some regions of interest and a rectangle will be painted in that region.

            The overlay is almost fine. Right now it's able to draw random rectangles and while the background is transparent you can click through the background. The problem is that I can't click through the rectangles.

            Running the example on macOS, clicks also don't pass through the transparent region. I'm surprised they do on Windows.

            I've tried the WA_TransparentForMouseEvents attribute, but it didn't work correctly. When I set this attribute the buttons stop working (I would expect this behaviour, and I don't care since the buttons are just for debuging), but I still can't click through the buttons or the rectangles.

            This is my code sample:

            if __name__ == "__main__":
                app = QApplication(sys.argv)
                main = QStackedWidget()
                main.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
                main.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
                main.move(0, 0)
                overlay = OverlayScreen()
                main.addWidget(overlay)
                main.show()
            

            Is there a reason to add the QMainWindow-based overlay to a QStackedWidget? I would guess that's the problem. Even though the overlay doesn't accept mouse input, the widget it is embedded in can, and the QWindow looks like a normal input accepting window to the OS.

            This works for me with macOS, as far as I understand the problem. The buttons and extraneous code have been removed for simplicity.

            import sys
            import random
            
            from PyQt5.QtCore import Qt
            from PyQt5.QtGui import QBrush, QColor, QPainter, QPen, QGuiApplication
            from PyQt5.QtWidgets import QApplication, QWidget
            
            
            class OverlayScreen(QWidget):
                def __init__(self, *args, **kwargs):
                    super().__init__(*args, **kwargs)
                    self.screen = QGuiApplication.screens()[0]
                    self.setFixedHeight(self.screen.size().width())
                    self.setFixedWidth(self.screen.size().height())
                    self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents)
            
                    self.rectangles = []
                    self.draw_rectangle()
                    self.draw_rectangle()
                    self.draw_rectangle()
            
                def draw_rectangle(self):
                    rect = [random.randint(151, self.screen.size().height() - 1),
                            random.randint(101, self.screen.size().width() - 1),
                            random.randint(1, 150),
                            random.randint(1, 100)]
                    self.rectangles.append(rect)
                    self.update()
            
                def paintEvent(self, event):
                    super().paintEvent(event)
                    painter = QPainter(self)
                    painter.setPen(QPen(Qt.GlobalColor.green, 1))
                    painter.setBrush(QBrush(QColor(0, 255, 0, 80), Qt.BrushStyle.SolidPattern))
                    for rect in self.rectangles:
                        painter.drawRect(*rect)
                    painter.end()
            
            
            if __name__ == "__main__":
                app = QApplication(sys.argv)
                overlay = OverlayScreen()
                overlay.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
                overlay.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint )
                # WindowTransparentForInput can be used instead of WA_TransparentForMouseEvents
                #overlay.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint | Qt.WindowTransparentForInput)
                overlay.show()
            
                try:
                    sys.exit(app.exec())
                except Exception:
                    print("Error")
            
            I Offline
            I Offline
            igonro
            wrote on last edited by
            #5

            @jeremy_k Yes. Someone told me that clicks don't pass through in Ubuntu too, but in Windows it really works (but only where the app it's 100% transparent).

            I add the QMainWindow to a QStackedWidget because is the method I use to navigate through different views. In the full code I also have a welcome screen, login screen... Is there a better way for navigating through different views? I saw this method in a Youtube tutorial.

            Your code is working fine for me. I will try to adapt the code without using the QStackedWidget if possible. Thank you so much :)

            jeremy_kJ 1 Reply Last reply
            0
            • I igonro

              @jeremy_k Yes. Someone told me that clicks don't pass through in Ubuntu too, but in Windows it really works (but only where the app it's 100% transparent).

              I add the QMainWindow to a QStackedWidget because is the method I use to navigate through different views. In the full code I also have a welcome screen, login screen... Is there a better way for navigating through different views? I saw this method in a Youtube tutorial.

              Your code is working fine for me. I will try to adapt the code without using the QStackedWidget if possible. Thank you so much :)

              jeremy_kJ Online
              jeremy_kJ Online
              jeremy_k
              wrote on last edited by
              #6

              @igonro said in How to make QPainter elements clickable-through using PyQt:

              @jeremy_k Yes. Someone told me that clicks don't pass through in Ubuntu too, but in Windows it really works (but only where the app it's 100% transparent).

              I add the QMainWindow to a QStackedWidget because is the method I use to navigate through different views. In the full code I also have a welcome screen, login screen... Is there a better way for navigating through different views? I saw this method in a Youtube tutorial.

              That sounds like a reasonable use, but the QStackedWidget should also be set transparent to input events while the overlay is displayed.

              Your code is working fine for me. I will try to adapt the code without using the QStackedWidget if possible. Thank you so much :)

              Happy to hear it.

              Asking a question about code? http://eel.is/iso-c++/testcase/

              I 1 Reply Last reply
              1
              • jeremy_kJ jeremy_k

                @igonro said in How to make QPainter elements clickable-through using PyQt:

                @jeremy_k Yes. Someone told me that clicks don't pass through in Ubuntu too, but in Windows it really works (but only where the app it's 100% transparent).

                I add the QMainWindow to a QStackedWidget because is the method I use to navigate through different views. In the full code I also have a welcome screen, login screen... Is there a better way for navigating through different views? I saw this method in a Youtube tutorial.

                That sounds like a reasonable use, but the QStackedWidget should also be set transparent to input events while the overlay is displayed.

                Your code is working fine for me. I will try to adapt the code without using the QStackedWidget if possible. Thank you so much :)

                Happy to hear it.

                I Offline
                I Offline
                igonro
                wrote on last edited by
                #7

                @jeremy_k Ohh, you're right. I've tried setting the QStackedWidget to transparent and it works. The problem I'm facing now is that in some windows (welcome and login) I need it to be clickable and in the overlay window I need to make it clickable through. But it seems that changing the Qt.WidgetAttribute.WA_TransparentForMouseEvents attribute during the execution doesn't work.

                Do you have any idea of why is this happening?

                1 Reply Last reply
                0
                • I Offline
                  I Offline
                  igonro
                  wrote on last edited by igonro
                  #8

                  I've updated the code sample in order to make it work with shortcuts (I think it's easier this way).

                  When I add the main.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents) line, it is 100% clickable through, and it works as intended; but I can't make it toggleable. The Ctrl+C shortcut is not working. :(

                  Is there any problem with the setAttribute() function? Maybe I have to call another function (instead of repaint()) to take effect?

                  import sys
                  from PyQt6.QtCore import Qt
                  from PyQt6.QtGui import QBrush, QColor, QKeySequence, QPainter, QPen, QShortcut
                  from PyQt6.QtWidgets import QApplication, QMainWindow, QStackedWidget
                  import numpy as np
                  
                  
                  class OverlayScreen(QMainWindow):
                      def __init__(self):
                          super().__init__()
                          self.setFixedHeight(1080)
                          self.setFixedWidth(1920)
                          self.setObjectName("overlay")
                          self.setStyleSheet("QMainWindow#overlay {background-color: rgba(0, 0, 0, 125)}")
                          self.bg_transparent = False
                          self.clickable_thr = False
                  
                          self.toggle_short = QShortcut(QKeySequence("Ctrl+T"), self)
                          self.toggle_short.activated.connect(self.toggle_background)
                          self.draw_short = QShortcut(QKeySequence("Ctrl+D"), self)
                          self.draw_short.activated.connect(self.draw_rectangle)
                          self.rectangles = []
                          self.clickable_short = QShortcut(QKeySequence("Ctrl+C"), self)
                          self.clickable_short.activated.connect(self.clickable_through)
                          self.close_short = QShortcut(QKeySequence("Ctrl+X"), self)
                          self.close_short.activated.connect(sys.exit)
                  
                      def toggle_background(self):
                          self.bg_transparent = not self.bg_transparent
                          if self.bg_transparent:
                              print("Transparency ON")
                              self.setStyleSheet("QMainWindow#overlay {background-color: transparent}")
                          else:
                              print("Transparency OFF")
                              self.setStyleSheet("QMainWindow#overlay {background-color: rgba(0, 0, 0, 125)}")
                  
                      def clickable_through(self):
                          self.clickable_thr = not self.clickable_thr
                          if self.clickable_thr:
                              print("Clickable through ON")
                              main.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, True)
                              self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, True)
                          else:
                              print("Clickable through OFF")
                              main.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, False)
                              self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, False)
                          self.repaint()
                  
                      def draw_rectangle(self):
                          print("Draw rectangle")
                          rect = [np.random.randint(1920 - 150),
                                  np.random.randint(1080 - 100),
                                  np.random.randint(150),
                                  np.random.randint(100)]
                          self.rectangles.append(rect)
                          self.update()
                  
                      def paintEvent(self, event):
                          painter = QPainter(self)
                          painter.setPen(QPen(Qt.GlobalColor.green, 1))
                          painter.setBrush(QBrush(QColor(0, 255, 0, 80), Qt.BrushStyle.SolidPattern))
                          for rect in self.rectangles:
                              painter.drawRect(*rect)
                          painter.end()
                  
                  
                  if __name__ == "__main__":
                      app = QApplication(sys.argv)
                      main = QStackedWidget()
                      # main.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents)
                      main.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
                      main.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
                      main.move(0, 0)
                      overlay = OverlayScreen()
                      main.addWidget(overlay)
                      main.show()
                  
                      try:
                          sys.exit(app.exec())
                      except Exception:
                          print("Error")
                  
                  1 Reply Last reply
                  0
                  • jeremy_kJ Online
                    jeremy_kJ Online
                    jeremy_k
                    wrote on last edited by jeremy_k
                    #9

                    https://code.woboq.org/qt5/qtbase/src/widgets/kernel/qwidget.cpp.html#1120

                    When WA_TransparentForMouseEvents is set on a top level widget, it sets the WindowTransparentForInput window flag. This explains why the keyboard shortcut doesn't work. The window won't receive keyboard input.

                    https://code.woboq.org/qt5/qtbase/src/widgets/kernel/qwidget.cpp.html#11444

                    Changing WA_TransparentForMouseEvents is a no-op for Qt5 and 6.

                    Directly applying or removing the Qt::WindowTransparentForInput window flag appears to work. I found it necessary to show() the top level widget after toggling.

                    Asking a question about code? http://eel.is/iso-c++/testcase/

                    I 1 Reply Last reply
                    1
                    • jeremy_kJ jeremy_k

                      https://code.woboq.org/qt5/qtbase/src/widgets/kernel/qwidget.cpp.html#1120

                      When WA_TransparentForMouseEvents is set on a top level widget, it sets the WindowTransparentForInput window flag. This explains why the keyboard shortcut doesn't work. The window won't receive keyboard input.

                      https://code.woboq.org/qt5/qtbase/src/widgets/kernel/qwidget.cpp.html#11444

                      Changing WA_TransparentForMouseEvents is a no-op for Qt5 and 6.

                      Directly applying or removing the Qt::WindowTransparentForInput window flag appears to work. I found it necessary to show() the top level widget after toggling.

                      I Offline
                      I Offline
                      igonro
                      wrote on last edited by igonro
                      #10

                      @jeremy_k I think I didn't explain it very well. When I add the main.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents) line, it is 100% clickable through, but I can't make it toggleable, the Ctrl+C shortcut is working (this is, "Clickable through ON/OFF" is being printed), but it doesn't toggle the click-through behaviour: it always remains as it is.

                      But yes, your solution is perfect! I've changed the setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents) for the setWindowFlag(Qt.WindowType.WindowTransparentForInput) and after applying the .show() it works as intended!

                      Thank you very much!

                      1 Reply Last reply
                      0
                      • I igonro

                        I am trying to create a desktop application for Windows 10 using PyQt.

                        The application will be an overlay, so it has to be transparent, clickable-through and always on top. An object detector will detect some regions of interest and a rectangle will be painted in that region.

                        The overlay is almost fine. Right now it's able to draw random rectangles and while the background is transparent you can click through the background. The problem is that I can't click through the rectangles.

                        I've tried the WA_TransparentForMouseEvents attribute, but it didn't work correctly. When I set this attribute the buttons stop working (I would expect this behaviour, and I don't care since the buttons are just for debuging), but I still can't click through the buttons or the rectangles.

                        This is my code sample:

                        import sys
                        from PyQt6.QtCore import Qt
                        from PyQt6.QtGui import QBrush, QColor, QPainter, QPen
                        from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QStackedWidget
                        import numpy as np
                        
                        
                        class OverlayScreen(QMainWindow):
                            def __init__(self):
                                super().__init__()
                                self.setFixedHeight(1080)
                                self.setFixedWidth(1920)
                                self.setObjectName("overlay")
                                self.setStyleSheet("QMainWindow#overlay {background-color: rgba(0, 0, 0, 125)}")
                                self.bg_transparent = False
                        
                                self.toggle_btn = QPushButton("Toggle", self)
                                self.toggle_btn.setGeometry(200, 150, 100, 30)
                                self.toggle_btn.clicked.connect(self.toggle_background)
                                self.draw_btn = QPushButton("Draw rectangle", self)
                                self.draw_btn.setGeometry(320, 150, 100, 30)
                                self.draw_btn.clicked.connect(self.draw_rectangle)
                                self.rectangles = []
                        
                                self.close_btn = QPushButton("Close", self)
                                self.close_btn.setGeometry(200, 200, 100, 30)
                                self.close_btn.clicked.connect(sys.exit)
                        
                            def toggle_background(self):
                                self.bg_transparent = not self.bg_transparent
                                if self.bg_transparent:
                                    self.setStyleSheet("QMainWindow#overlay {background-color: transparent}")
                                else:
                                    self.setStyleSheet("QMainWindow#overlay {background-color: rgba(0, 0, 0, 125)}")
                        
                            def draw_rectangle(self):
                                # self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents)
                                rect = [np.random.randint(1920 - 150),
                                        np.random.randint(1080 - 100),
                                        np.random.randint(150),
                                        np.random.randint(100)]
                                self.rectangles.append(rect)
                                self.update()
                        
                            def paintEvent(self, event):
                                painter = QPainter(self)
                                painter.setPen(QPen(Qt.GlobalColor.green, 1))
                                painter.setBrush(QBrush(QColor(0, 255, 0, 80), Qt.BrushStyle.SolidPattern))
                                for rect in self.rectangles:
                                    painter.drawRect(*rect)
                                painter.end()
                        
                        
                        if __name__ == "__main__":
                            app = QApplication(sys.argv)
                            main = QStackedWidget()
                            main.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
                            main.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
                            main.move(0, 0)
                            overlay = OverlayScreen()
                            main.addWidget(overlay)
                            main.show()
                        
                            try:
                                sys.exit(app.exec())
                            except Exception:
                                print("Error")
                        
                        enjoysmathE Offline
                        enjoysmathE Offline
                        enjoysmath
                        wrote on last edited by
                        #11

                        @igonro That's the sexiest MWE I've ever "scene"!

                        https://github.com/enjoysmath
                        https://math.stackexchange.com/users/26327/exercisingmathematician

                        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