这段代码实现了一个为QWidget添加阴影和圆角边框效果的辅助类。以下是对代码的分析和一些改进建议:
代码分析
优点:
-
使用了PIMPL(Private Implementation)模式,隐藏实现细节
-
支持高DPI屏幕(devicePixelRatio处理)
-
使用九宫格技术绘制阴影,性能较好
-
支持圆角边框和自定义边框样式
源代码分享 :
源文件 :
#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);
}
头文件 :


评论(0)