QWidget 鼠标事件穿透

假设现在有两个重叠显示的 QWidget 部件,widget_1 与 widget_2。二者无父子关系,只是位置重叠,widget_1 在 widget_2 之上,如下图所示。

这个时候如果鼠标点击在 widget_1 上,widget_2 是不会响应鼠标事件的。因为事件被位于上层的 widget_1 捕获了。

如果我们想让鼠标事件穿透 widget_1,由 widget_2 捕获。就可以给 widget_1 设置 WA_TransparentForMouseEvents 属性,让它对所有鼠标事件“透明”。

widget_1.setAttribute(QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents)

QLabel 显示富文本时会吞掉鼠标事件

今天还遇到一个问题,当 QLabel 作为子控件的时候,如果是 PlainText 模式,那么在 QLabel 上触发的鼠标事件会自动传递给父控件。但如果 QLabel 处于 RichText 模式,那么它会响应并且吞掉鼠标事件!事件无法传递给父控件!

BUG 复现代码如下:

class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        self.label = MyLabel(self)
        self.label.resize(200, 50)
        self.label.setStyleSheet("border: 1px solid black;")

        text = "Test mouse events on here"
        self.label.setText(text)
        self.label.setText("<p style='color:red;'>{}</p>".format(text))
        # self.label.setAttribute(QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents)

    def mouseReleaseEvent(self, e):
        if e.button() == QtCore.Qt.LeftButton:
            print("Left")

        if e.button() == QtCore.Qt.RightButton:
            print("Right")
        pass

App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())

有两种解决办法:

(1)给 label 设置 setAttribute(QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents) ,这样 label 自己就不响应鼠标事件,也不会吞掉事件而是直接传递给父节点。

(2)派生 QLabel,重写 mouseReleaseEvent() 方法,在该方法中,判断如果可能是富文本,就手动将鼠标事件传递给父节点。

def mouseReleaseEvent(self, event):    
    if QtGui.Qt.mightBeRichText(self.text()):
        self.parent().mouseReleaseEvent(event)

    super().mouseReleaseEvent(event)
    pass

 

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top