先看目标效果:
想要实现封面图标的遮罩效果,有两个思路:
一、在鼠标移动到这个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,最大值是255
painter.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_();
}
else
m_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
移到顶层。