先看目标效果:
想要实现封面图标的遮罩效果,有两个思路:
一、在鼠标移动到这个item上面时,重新绘制pixmap
例如以下代码:
#include <QApplication>
#include <QWidget>
#include <QPixmap>
#include <QLabel>
#include <QPainter>
#include <QColor>class TransparentOverlayWidget : public QWidget
{
public:TransparentOverlayWidget(QWidget *parent = nullptr) : QWidget(parent){// 创建 QLabel 来显示带有半透明矩形的图像label = new QLabel(this);label->setFixedSize(500,500);label->setScaledContents(true);}void paintEvent(QPaintEvent *event) override {QWidget::paintEvent(event);pixmap = QPixmap("background.jpg");// 创建QPainter并在QPixmap上绘制QPainter painter(&pixmap);// 设置半透明度,0.0为完全透明,1.0为完全不透明painter.setOpacity(0.5);// 设置绘制颜色,带有透明度painter.setBrush(QColor(255, 0, 0, 127)); // 透明度为127,最大值是255painter.setPen(Qt::NoPen);if(m_isHover) {// 绘制一个半透明矩形painter.drawRect(50, 50, 200, 150);}// 完成绘制painter.end();label->setPixmap(pixmap);}void enterEvent(QEnterEvent *event) {QWidget::enterEvent(event);m_isHover = true;qDebug()<<"进入widget";update();}void leaveEvent(QEvent *event) {QWidget::leaveEvent(event);m_isHover = false;qDebug()<<"离开widget";update();}
private:bool m_isHover = false;QLabel *label{};QPixmap pixmap;
};int main(int argc, char *argv[])
{QApplication app(argc, argv);TransparentOverlayWidget widget;widget.show();return app.exec();
}
值得注意的是:pixmap = QPixmap("background.jpg");这行代码的位置的考究。。。
每次绘制前重新初始化 :若是将这行代码放在构造函数里面就起不到透明的效果。原因如下:
确保在每次paintEvent
时,QPixmap
都是初始的未被修改的图像,而不是之前被修改的版本。否则你可能会在一个已经绘制了半透明矩形的QPixmap
上再次绘制半透明矩形,这会导致透明度的叠加不正确。
二、新建Mask的QWidget类
Mask.h:
//
// Created by WeiWang on 24-9-18.
//#ifndef MASK_H
#define MASK_H
#include<QWidget>
#include<QPainter>class Mask : QWidget
{
public:Mask(QWidget *parent = nullptr):QWidget(parent) {setWindowFlags(Qt::FramelessWindowHint);this->setFixedSize(100,100);}void paintEvent(QPaintEvent *event) {QPainter painter(this);QColor color(0,0,0,160);// 设置绘制颜色,带有透明度painter.setBrush(color);painter.setPen(Qt::NoPen);painter.fillRect(rect(),color);}void move_(int x,int y){this->move(x,y);};void hide_(){ this->hide();};void show_(){ this->show();};void raise_(){ this->raise();};
};#endif //MASK_H
main.cpp:
#include <QApplication>#include <QWidget>#include <QPixmap>#include <QLabel>#include <QPainter>#include <QColor>#include "Mask.h"class TransparentOverlayWidget : public QWidget{public:TransparentOverlayWidget(QWidget *parent = nullptr): QWidget(parent){this->setFixedSize(500,500);// 加载图像QPixmap pixmap("F:\\code_review\\Qt-WorkSpace\\fight\\KuGouApp\\KuGouStart\\Res\\tabIcon\\music-cover.jpg");// 创建 QLabel 来显示带有半透明矩形的图像label = new QLabel(this);label->move(100,100);label->setScaledContents(true);label->setPixmap(pixmap);label->setFixedSize(100,100);label->setAlignment(Qt::AlignCenter);m_mask = new Mask(this);m_mask->move_(100,100);m_mask->hide_();}void paintEvent(QPaintEvent *event)override {if(this->m_isHover) {m_mask->show_();//m_mask->raise_();}elsem_mask->hide_();}void enterEvent(QEnterEvent *event) {QWidget::enterEvent(event);qDebug()<<"进入widget";m_isHover = true;update();}void leaveEvent(QEvent *event) {QWidget::leaveEvent(event);qDebug()<<"离开widget";m_isHover = false;update();}private:QLabel *label{};bool m_isHover = false;Mask *m_mask{};};int main(int argc, char *argv[]){QApplication app(argc, argv);TransparentOverlayWidget widget;widget.show();return app.exec();
}
注意:此处有两个坑
①mask的初始化位置:
一旦使用了如上图所示的初始化顺序,即先初始化mask再初始化lab,那么到了后面遮罩会被label挡住,原因如下:
在 Qt 中,子控件的绘制顺序遵循父控件的层次结构和堆叠顺序。默认情况下,父控件的子控件会按照其创建的顺序绘制。因此,如果
Mask
是TransparentOverlayWidget
的子控件,并且在层次结构中比QLabel
更早创建或被覆盖,那么QLabel
会在Mask
之上绘制,导致Mask
被遮住。
所以一定要让mask的初始化在label之后。
② 硬要在构造列表初始化
如果一定要在构造列表初始化的话,那么就需要使用
将 Mask
设置为在最顶层显示: 使用 raise()
函数将 Mask
移到顶层。