Как сделать элементы QPainter кликабельными с помощью PyQt

Я пытаюсь создать настольное приложение для Windows 10 с помощью PyQt.

Приложение будет оверлеем, поэтому оно должно быть прозрачным, кликабельным и всегда сверху. Детектор объектов обнаружит некоторые интересующие области, и в этой области будет нарисован прямоугольник.

Накладка почти в порядке. Прямо сейчас он может рисовать случайные прямоугольники, и, пока фон прозрачен, вы можете щелкать фон. Проблема в том, что я не могу нажимать на прямоугольники.

Я попробовал атрибут WA_TransparentForMouseEvents, но он не работал правильно. Когда я устанавливаю этот атрибут, кнопки перестают работать (я ожидал такого поведения, и мне все равно, поскольку кнопки предназначены только для отладки), но я все еще не могу нажимать кнопки или прямоугольники.

Это мой пример кода:

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")

person igonro    schedule 04.06.2021    source источник
comment
Я не могу воспроизвести переход по клику в Linux. В любом случае, установка WA_TransparentForMouseEvents в событии рисования бесполезна, так как эти вещи совершенно не связаны между собой: пытаться установить этот атрибут в событиях рисования — плохая идея (такие события могут происходить очень часто), а установка атрибута действует на все виджет в любом случае. Возможно, вам следует подумать о маскировании, см. этот частично связанный ответ: Можно ли создать QMainWindow только с внешней границей?.   -  person musicamante    schedule 04.06.2021