QT 事件仅对部分小部件透明

QT Event transparency only for part of the widget

本文关键字:小部 透明 事件 QT      更新时间:2023-10-16

软件显示 3 个小部件:

  • 主窗口
  • 内容小部件,覆盖大部分主窗口
  • 自定义小部件
  • ,涵盖主窗口和内容小部件的一部分。

自定义小部件有一个需要Event-opaque的部分(定义为QRect),而周围的区域必须Event-transparent

我尝试过:

setAttribute(Qt::WA_TransparentForMouseEvents);

但是自定义的所有子小部件也变得透明。

我也尝试了setMask,但随后自定义小部件无法在周围区域绘制。

如何实现这种部分事件透明性?

示例(它没有解释完整的问题,只是添加一个测试解决方案的基础):

主.cpp

#include "transparentwidget.hpp"
#include "normalwidget.hpp"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    // Main Window
    NormalWidget window;
    window.resize(500,500);
    window.setObjectName("window");
    window.setStyleSheet("background-color: rgba(0,0,128,128); ");
    // Content window
    NormalWidget content(&window);
    content.setObjectName("content");
    content.resize(400, 400);
    content.move(0,0);
    content.setStyleSheet("background-color: rgba(128,0,0,128);");
    TransparentWidget custom(&window);
    custom.setObjectName("custom");
    custom.resize(500, 200);
    custom.setStyleSheet("background-color:rgba(0,128,0,128);");
    window.show();
    return a.exec();
}

transparentwidget.hpp

#ifndef TRANSPARENTWIDGET_H
#define TRANSPARENTWIDGET_H
#include <QWidget>
#include <QStyleOption>
#include <QPainter>
#include <QDebug>
#include <QEvent>
// This widget shall be transparent in some parts
class TransparentWidget : public QWidget
{
    Q_OBJECT
public:
    explicit TransparentWidget(QWidget *parent = 0): QWidget(parent)
    {
        // Start of solution with WA_TransparentForMouseEvents (not working)
        setAttribute(Qt::WA_TransparentForMouseEvents);
        // end solution with WA_TransparentForMouseEvents
    }
    ~TransparentWidget(){}
protected:
    QRect opaqueRect = QRect(0,0,400,100);
    void paintEvent(QPaintEvent *)
    {
        // Solution with setMask, not working
        QRegion reg(opaqueRect);
        setMask(reg);
        // end of setMask solution
        QStyleOption opt;
        opt.init(this);
        QPainter p(this);
        style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
    }
    bool event(QEvent *event)
    {
        // Starting of solution with event propagation (not working)
        if (event->type() == QEvent::MouseButtonPress ||
            event->type() == QEvent::MouseButtonRelease)
        {
            QMouseEvent* e = static_cast<QMouseEvent*>(event);
            if (e && !opaqueRect.contains(e->pos()) return false;
        }
        // end solution with event propagation.
        if (event->type() == QEvent::MouseButtonPress) qDebug() << "Press: " << objectName();
        else if(event->type() == QEvent::MouseButtonRelease) qDebug() << "Release: " << objectName();
        return QWidget::event(event);
    }
};
#endif

normalwidget.hpp

#ifndef NORMALWIDGET_H
#define NORMALWIDGET_H
#include <QWidget>
#include <QStyleOption>
#include <QPainter>
#include <QDebug>
#include <QEvent>
// Widgets that are not event-transparent
class NormalWidget : public QWidget
{
    Q_OBJECT
public:
    explicit NormalWidget(QWidget *parent = 0): QWidget(parent){}
    ~NormalWidget(){}
protected:
    void paintEvent(QPaintEvent *)
    {
        QStyleOption opt;
        opt.init(this);
        QPainter p(this);
        style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
    }
    bool event(QEvent *event)
    {
        if (event->type() == QEvent::MouseButtonPress) qDebug() << "Press: " << objectName();
        else if(event->type() == QEvent::MouseButtonRelease) qDebug() << "Release: " << objectName();
    }
};
#endif // NORMALWIDGET_H

就像文档说的:

启用后,此属性将禁用将鼠标事件传递到 小组件及其子项

解决方案是忽略TransparentWidget::event()中的所有鼠标事件。如果在 TransparentWidget 的子项上执行鼠标事件,则该事件将由该子项使用,否则将传递给TransparentWidget的父项:

bool TransparentWidget::event(QEvent *event)
{
    if (event->type() == QEvent::MouseButtonPress ||
        event->type() == QEvent::MouseButtonRelease ||
        event->type() == QEvent::MouseButtonRelease)
        return false;
    else
        return QWidget::event(event);
}