通过paintEvent来实现的,绘制方形的阴影没问题,但是绘制圆角阴影的话,发现圆角不够圆润,而且有断裂的感觉。
#pragma once
#include <QWidget>
#include <QPaintEvent>
class CShadowWindow2 : public QWidget
{
Q_OBJECT
public:
explicit CShadowWindow2(QWidget* pShadowWidget,QWidget *parent = Q_NULLPTR);
virtual ~CShadowWindow2();
void SetShadowSize(int iSize);
int GetShadowSize() const;
void SetShadowColor(const QColor& color);
protected:
void paintEvent(QPaintEvent* pEvent) override;
void resizeEvent(QResizeEvent* pEvent) override;
void mousePressEvent(QMouseEvent* pEvent) override;
void mouseReleaseEvent(QMouseEvent* pEvent) override;
void mouseMoveEvent(QMouseEvent* pEvent) override;
void InitConstruct();
enum Direction
{
OUTER,
LEFT_TOP,
LEFT_BOTTOM,
RIGHT_TOP,
RIGHT_BOTTOM,
CENTER,
LEFT,
RIGHT,
TOP,
BOTTOM
};
Direction CalcDirection(const QPoint& pt);
void SetMouseCursorStyle(Direction direction);
void DragAndResizeWidget(CShadowWindow2::Direction direction, const QPoint& ptOffset);
private:
int m_iShadowSize;
QColor m_shadowColor;
QWidget* m_pShadowWidget;
QPoint m_ptPreGlobal;
Direction m_Direction;
};
实现:
#include "CShadowWindow2.h"
#include <QPainter>
#include <QBrush>
#include <QtMath>
#include <QDebug>
CShadowWindow2::CShadowWindow2(QWidget* pShadowWidget, QWidget *parent)
: QWidget(parent),
m_pShadowWidget(pShadowWidget),
m_iShadowSize(20),
m_shadowColor(0, 0, 0, 255)
{
//设置窗口无边框
setWindowFlags(Qt::FramelessWindowHint);
//设置窗口背景透明
setAttribute(Qt::WA_TranslucentBackground, true);
InitConstruct();
}
CShadowWindow2::~CShadowWindow2()
{
}
void CShadowWindow2::InitConstruct()
{
//关联一个父窗口
m_pShadowWidget->setParent(this);
//设置阴影窗口大小
const QSize sz = m_pShadowWidget->size();
resize(m_iShadowSize + sz.width(), m_iShadowSize + sz.height());
m_pShadowWidget->move(m_iShadowSize, m_iShadowSize);
/*当鼠标不按下时,qt为了节省消耗,不会响应mousemove事件,所以需要设置true,这样即使不按下鼠标也会收到鼠标移动事件
子窗口也要设置,是因为鼠标移动事件发生在了子窗口上,被拦截了
*/
setMouseTracking(true);
m_pShadowWidget->setMouseTracking(true);
}
void CShadowWindow2::SetShadowSize(int iSize)
{
if (iSize != m_iShadowSize && iSize>0)
{
m_iShadowSize = iSize;
QSize sz = m_pShadowWidget->size();
resize(sz.width() + m_iShadowSize * 2, m_pShadowWidget->height() + m_iShadowSize * 2);
}
}
int CShadowWindow2::GetShadowSize() const
{
return m_iShadowSize;
}
void CShadowWindow2::SetShadowColor(const QColor& color)
{
if (color != m_shadowColor)
{
m_shadowColor = color;
update();
}
}
void CShadowWindow2::resizeEvent(QResizeEvent*)
{
QSize sz = size();
m_pShadowWidget->setGeometry(m_iShadowSize, m_iShadowSize,
qAbs(sz.width() - m_iShadowSize * 2), qAbs(sz.height() - m_iShadowSize * 2));
}
void CShadowWindow2::paintEvent(QPaintEvent*)
{
//下列方式绘制的圆角阴影,边角有毛刺
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true);
qreal rStep = (1 - m_shadowColor.redF()) / m_iShadowSize;
qreal gStep = (1 - m_shadowColor.greenF()) / m_iShadowSize;
qreal bStep = (1 - m_shadowColor.blueF()) / m_iShadowSize;
qreal bAlpha = m_shadowColor.alphaF() / m_iShadowSize;
QColor color;
color.setRedF(m_shadowColor.redF());
color.setGreenF(m_shadowColor.greenF());
color.setBlueF(m_shadowColor.blueF());
color.setAlpha(m_shadowColor.alpha());
for (int i = 0; i < m_iShadowSize; ++i)
{
QPainterPath path;
path.setFillRule(Qt::WindingFill);
int iShadowSize = m_iShadowSize - i;
#if 0
path.addRoundedRect(iShadowSize, iShadowSize,
width() - iShadowSize * 2, height() - iShadowSize * 2,
m_iShadowSize, m_iShadowSize);
#else
path.addRect(iShadowSize, iShadowSize,
width() - iShadowSize * 2, height() - iShadowSize * 2);
#endif
color.setRedF(color.redF() + rStep);
color.setGreenF(color.greenF() + gStep);
color.setBlueF(color.blueF() + gStep);
color.setAlphaF(qAbs(color.alphaF() - bAlpha));
painter.setPen(color);
painter.drawPath(path);
}
}
CShadowWindow2::Direction CShadowWindow2::CalcDirection(const QPoint& pt)
{
if (pt.x() < m_iShadowSize && pt.y() < m_iShadowSize)
{
return LEFT_TOP;
}
else if (pt.x() < m_iShadowSize
&&pt.y() > m_iShadowSize && pt.y() < rect().height() - m_iShadowSize)
{
return LEFT;
}
else if (pt.x() < m_iShadowSize &&pt.y() > rect().height() - m_iShadowSize)
{
return LEFT_BOTTOM;
}
else if (pt.x() > rect().width() - m_iShadowSize && pt.y() < m_iShadowSize)
{
return RIGHT_TOP;
}
else if (pt.x() > rect().width() - m_iShadowSize
&& pt.y() > m_iShadowSize && pt.y() < rect().height() - m_iShadowSize)
{
return RIGHT;
}
else if (pt.x() > rect().width() - m_iShadowSize
&& pt.y() > rect().height() - m_iShadowSize)
{
return RIGHT_BOTTOM;
}
else if (pt.x() > m_iShadowSize&&pt.x() < rect().width() - m_iShadowSize
&&pt.y() < m_iShadowSize)
{
return TOP;
}
else if (pt.x() > m_iShadowSize&&pt.x() < rect().width() - m_iShadowSize
&&pt.y() > rect().height() - m_iShadowSize)
{
return BOTTOM;
}
else if (pt.x() >= m_iShadowSize&&pt.y() >= m_iShadowSize
&&pt.x() <= rect().width() - m_iShadowSize&&pt.y() <= rect().height() - m_iShadowSize)
{
return CENTER;
}
return OUTER;
}
void CShadowWindow2::SetMouseCursorStyle(Direction direction)
{
switch (direction)
{
case TOP:
case BOTTOM:
setCursor(Qt::SizeVerCursor);
break;
case LEFT:
case RIGHT:
setCursor(Qt::SizeHorCursor);
break;
case LEFT_TOP:
case RIGHT_BOTTOM:
setCursor(Qt::SizeFDiagCursor);
break;
case RIGHT_TOP:
case LEFT_BOTTOM:
setCursor(Qt::SizeBDiagCursor);
break;
case CENTER:
if (m_ptPreGlobal.isNull())
{
setCursor(Qt::ArrowCursor);
}
else
{
setCursor(Qt::SizeAllCursor);
}
break;
default:
setCursor(Qt::ArrowCursor);
}
}
void CShadowWindow2::DragAndResizeWidget(CShadowWindow2::Direction direction, const QPoint& ptOffset)
{
QRect rect = geometry();
switch (direction)
{
case TOP:
rect.setTop(rect.top() + ptOffset.y());
break;
case BOTTOM:
rect.setBottom(rect.bottom() + ptOffset.y());
break;
case LEFT:
rect.setLeft(rect.left() + ptOffset.x());
break;
case RIGHT:
rect.setRight(rect.right() + ptOffset.x());
break;
case LEFT_TOP:
rect.setTopLeft(rect.topLeft() + ptOffset);
break;
case RIGHT_BOTTOM:
rect.setBottomRight(rect.bottomRight() + ptOffset);
break;
case RIGHT_TOP:
rect.setTopRight(rect.topRight() + ptOffset);
break;
case LEFT_BOTTOM:
rect.setBottomLeft(rect.bottomLeft() + ptOffset);
break;
case CENTER:
break;
default:;
}
if (rect.width() < m_iShadowSize * 3 || rect.height() < m_iShadowSize * 3)
{
return;
}
setGeometry(rect);
return;
}
void CShadowWindow2::mousePressEvent(QMouseEvent* pEvent)
{
if (Qt::LeftButton == pEvent->button())
{
m_ptPreGlobal = pEvent->globalPos();
m_Direction = CalcDirection(pEvent->pos());
SetMouseCursorStyle(m_Direction);
}
}
void CShadowWindow2::mouseReleaseEvent(QMouseEvent* pEvent)
{
m_ptPreGlobal = QPoint();
setCursor(Qt::ArrowCursor);
}
void CShadowWindow2::mouseMoveEvent(QMouseEvent* pEvent)
{
if (Qt::LeftButton&pEvent->buttons())
{
SetMouseCursorStyle(m_Direction);
const QPoint ptNow = pEvent->globalPos();
const QPoint ptOffset = ptNow - m_ptPreGlobal;
m_ptPreGlobal = ptNow;
if (Direction::CENTER == m_Direction)
{
move(pos() + ptOffset);
}
else
{
DragAndResizeWidget(m_Direction, ptOffset);
}
}
else
{
SetMouseCursorStyle(CalcDirection(pEvent->pos()));
}
}
例子:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
auto pWidget = new QWidget();
pWidget->resize(200, 200);
pWidget->setStyleSheet(QString("background-color: yellow"));
auto pContainer = new CShadowWindow(pWidget);
pContainer->show();
return a.exec();
}