这段代码实现了一个为QWidget添加阴影和圆角边框效果的辅助类。以下是对代码的分析和一些改进建议:

代码分析

优点:

  1. 使用了PIMPL(Private Implementation)模式,隐藏实现细节

  2. 支持高DPI屏幕(devicePixelRatio处理)

  3. 使用九宫格技术绘制阴影,性能较好

  4. 支持圆角边框和自定义边框样式

 

源代码分享 :

源文件 :

#include “shadow_effect_helper.h”

#include <QPainter>
#include <QEvent>
#include <QTimer>
#include <QDialog>
#include <QBitmap>

#include <QGuiApplication>
#include <QScreen>
#include <QSize>

namespace
{
constexpr int BORDERMARGIN = 30;
constexpr int SHADOWWIDTH = 10;
const QSize SHADOWSIZE = QSize(133, 133);
}

class ShadowEffectHelperPrivate {

public:
ShadowEffectHelperPrivate(QWidget* sibling, ShadowEffectHelper* q)
: m_widget(sibling), m_bAutoClose(true), m_ratio(1.0), q(q),
m_roundedEnabled(false), m_borderWidth(1),
m_borderColor(QColor(255, 255, 255, 25)), m_cornerRadius(10)
{
// 九宫格阴影图 – 用于绘制阴影(必须要正方形图片)
m_pixmap = QPixmap(“:/common/shadow.png”);
QScreen *screen = QGuiApplication::primaryScreen();
m_ratio = screen ? screen->devicePixelRatio() : 1.0; // 获取当前屏幕缩放比(如125%时为1.25)
m_pixmap.setDevicePixelRatio(m_ratio);
QSize pixmapSize = SHADOWSIZE * m_ratio;
m_pixmap = m_pixmap.scaled(pixmapSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
m_shadowWidget = new QWidget(m_widget);
m_shadowWidget->setAttribute(Qt::WA_TransparentForMouseEvents);
m_shadowWidget->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
m_shadowWidget->setAttribute(Qt::WA_StyledBackground);
m_shadowWidget->setAttribute(Qt::WA_TranslucentBackground);
m_shadowWidget->setAttribute(Qt::WA_InputMethodTransparent);
m_widget->installEventFilter(q);
m_shadowWidget->installEventFilter(q);

if (auto dlg = qobject_cast<QDialog*>(m_widget)) {
QObject::connect(dlg, &QDialog::finished, q, [=](int result) {
Q_UNUSED(result);
m_shadowWidget->close();
});
}
}

~ShadowEffectHelperPrivate()
{
m_widget->removeEventFilter(q);
m_shadowWidget->removeEventFilter(q);
}

void setEnabled(bool enabled)
{
m_shadowWidget->setVisible(enabled);
if(enabled)
{
m_widget->installEventFilter(q);
m_shadowWidget->installEventFilter(q);
}
else
{
m_widget->removeEventFilter(q);
m_shadowWidget->removeEventFilter(q);
}
}

// 圆角边框功能
void setRoundedEnabled(bool enabled)
{
if (!m_widget) return;

m_roundedEnabled = enabled;
if (enabled)
{
applyRoundedMask();
m_widget->update();
}
else
{
m_widget->clearMask();
m_widget->update();
}
}

void setBorderStyle(int width, const QColor& color)
{
m_borderWidth = width;
m_borderColor = color;
if (m_widget)
{
m_widget->update();
}
}

void setCornerRadius(int radius)
{
m_cornerRadius = radius;
if (m_roundedEnabled && m_widget)
{
applyRoundedMask();
m_widget->update();
}
}

void repaintNinePatch()
{
int horzSplit = BORDERMARGIN + SHADOWWIDTH;
int vertSplit = BORDERMARGIN + SHADOWWIDTH;
auto shadowRc = m_shadowWidget->rect();
int x1 = shadowRc.left();
int x2 = x1 + horzSplit;
int x3 = shadowRc.right() – horzSplit;
int x4 = shadowRc.right();

int y1 = shadowRc.top();
int y2 = y1 + vertSplit;
int y3 = shadowRc.bottom() – vertSplit;
int y4 = shadowRc.bottom();

// 目标九宫格图标绘制
QRect tagRect1(x1, y1, x2 – x1, y2 – y1);
QRect tagRect2(x2, y1, x3 – x2, y2 – y1);
QRect tagRect3(x3, y1, x4 – x3, y2 – y1);

QRect tagRect4(x1, y2, x2 – x1, y3 – y2);
QRect tagRect6(x3, y2, x4 – x3, y3 – y2);

QRect tagRect7(x1, y3, x2 – x1, y4 – y3);
QRect tagRect8(x2, y3, x3 – x2, y4 – y3);
QRect tagRect9(x3, y3, x4 – x3, y4 – y3);

// 源九宫格图标绘制
horzSplit = (BORDERMARGIN + SHADOWWIDTH) * m_ratio;
vertSplit = (BORDERMARGIN + SHADOWWIDTH) * m_ratio;

auto pixRc = m_pixmap.rect();
x1 = pixRc.left();
x2 = x1 + horzSplit;
x3 = pixRc.right() – horzSplit;
x4 = pixRc.right();

y1 = pixRc.top();
y2 = y1 + vertSplit;
y3 = pixRc.bottom() – vertSplit;
y4 = pixRc.bottom();

QRect srcRect1(x1, y1, x2 – x1, y2 – y1);
QRect srcRect2(x2, y1, x3 – x2, y2 – y1);
QRect srcRect3(x3, y1, x4 – x3, y2 – y1);

QRect srcRect4(x1, y2, x2 – x1, y3 – y2);
QRect srcRect6(x3, y2, x4 – x3, y3 – y2);

QRect srcRect7(x1, y3, x2 – x1, y4 – y3);
QRect srcRect8(x2, y3, x3 – x2, y4 – y3);
QRect srcRect9(x3, y3, x4 – x3, y4 – y3);

QPainter painter(m_shadowWidget);
painter.drawPixmap(tagRect1, m_pixmap, srcRect1);
painter.drawPixmap(tagRect2, m_pixmap, srcRect2);
painter.drawPixmap(tagRect3, m_pixmap, srcRect3);

painter.drawPixmap(tagRect4, m_pixmap, srcRect4);
painter.drawPixmap(tagRect6, m_pixmap, srcRect6);

painter.drawPixmap(tagRect7, m_pixmap, srcRect7);
painter.drawPixmap(tagRect8, m_pixmap, srcRect8);
painter.drawPixmap(tagRect9, m_pixmap, srcRect9);
}

bool eventFilter(QObject* watched, QEvent* event)
{
if (watched == m_widget) {
if (event->type() == QEvent::Move)
{
resizeEffectFun();
}
else if (event->type() == QEvent::Show)
{
resizeEffectFun();
m_shadowWidget->show();

}
else if (event->type() == QEvent::Hide)
{
m_shadowWidget->hide();
}
else if (event->type() == QEvent::Close)
{
if (m_bAutoClose)
m_shadowWidget->close();
}
else if (event->type() == QEvent::Resize)
{
resizeEffectFun();
if (m_roundedEnabled)
{
applyRoundedMask();
}
}
else if (event->type() == QEvent::WindowActivate)
{
m_shadowWidget->update();
}
}
else if (watched == m_shadowWidget)
{
if (event->type() == QEvent::Paint)
{
if (m_widget->isVisible() && !m_widget->isMinimized())
{
repaintNinePatch();

if (m_roundedEnabled)
{
QPainter painter(m_shadowWidget);
painter.setRenderHint(QPainter::Antialiasing);

QRect widgetRect = m_widget->geometry();
QPoint shadowTopLeft = m_shadowWidget->mapFromGlobal(widgetRect.topLeft());
QRect borderRect(shadowTopLeft, widgetRect.size());
borderRect.adjust(-1, -1, 1, 1);
drawAdvancedBorder(painter, borderRect);
}
}
}
}

return false;
}

void resizeEffectFun()
{
QRect rc = m_widget->geometry();
rc.adjust(-BORDERMARGIN, -BORDERMARGIN, BORDERMARGIN, BORDERMARGIN);
m_shadowWidget->setGeometry(rc);
m_shadowWidget->setFixedSize(rc.size());
m_shadowWidget->update();
}

// 圆角遮罩功能
void applyRoundedMask()
{
if (!m_widget) return;

QBitmap bmp(m_widget->size());
bmp.fill(Qt::color0);

QPainter p(&bmp);
p.setRenderHint(QPainter::Antialiasing);
p.setPen(Qt::NoPen);
p.setBrush(Qt::color1);

// 绘制圆角矩形,遮罩半径比边框稍小确保边框完全可见
p.drawRoundedRect(bmp.rect(), m_cornerRadius – 1, m_cornerRadius – 1);

m_widget->setMask(bmp);
}

void drawAdvancedBorder(QPainter& painter, const QRect& borderRect)
{

painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);

QPen pen(m_borderColor);
pen.setWidth(m_borderWidth);
pen.setJoinStyle(Qt::MiterJoin);
pen.setCapStyle(Qt::SquareCap);
painter.setPen(pen);
painter.setBrush(Qt::NoBrush);

painter.drawRoundedRect(borderRect, m_cornerRadius, m_cornerRadius);
}

QWidget* m_widget;
QWidget* m_shadowWidget;
QPixmap m_pixmap;

bool m_bAutoClose;
qreal m_ratio;

bool m_roundedEnabled;
int m_borderWidth;
int m_cornerRadius;
QColor m_borderColor;

ShadowEffectHelper* q;
};

ShadowEffectHelper::ShadowEffectHelper(QWidget* sibling)
: QObject(nullptr), d(new ShadowEffectHelperPrivate(sibling, this))
{
}

ShadowEffectHelper::~ShadowEffectHelper()
{
}

void ShadowEffectHelper::set_enabled(bool enabled)
{
d->setEnabled(enabled);
}

void ShadowEffectHelper::set_auto_close(bool enabled)
{
d->m_bAutoClose = enabled;
}

void ShadowEffectHelper::set_rounded_enabled(bool enabled)
{
d->setRoundedEnabled(enabled);
}

void ShadowEffectHelper::set_border_style(int width, const QColor& color)
{
d->setBorderStyle(width, color);
}

void ShadowEffectHelper::set_corner_radius(int radius)
{
d->setCornerRadius(radius);
}

QWidget* ShadowEffectHelper::shadow_widget()
{
return d->m_shadowWidget;
}

bool ShadowEffectHelper::eventFilter(QObject* watched, QEvent* event)
{
return d->eventFilter(watched, event);
}

 

头文件 :

 

 

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。