通过QGraphicsDropShadowEffect来实现,主要思想就是:把无标题的透明窗体添加阴影后作为背景,然后把正常的窗体作为子窗口附加上去。
#pragma once
#include <QWidget>
#include <QResizeEvent>
class CShadowWindow : public QWidget
{
Q_OBJECT
public:
explicit CShadowWindow(QWidget* pShadowWidget, QWidget *parent = Q_NULLPTR);
virtual ~CShadowWindow();
void SetShadowSize(int iSize);
int GetShadowSize() const;
void SetShadowColor(const QColor& color);
void SetShadowBlurRadius(qreal blurRadius);
protected:
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(CShadowWindow::Direction direction, const QPoint& ptOffset);
private:
int m_iShadowSize;
QColor m_shadowColor;
QWidget* m_pShadowWidget;
qreal m_fBlurRadius;
QPoint m_ptPreGlobal;
Direction m_Direction;
};
代码实现:
#include "CShadowWindow.h"
#include <QtMath>
#include <QGraphicsDropShadowEffect>
#include <QDebug>
CShadowWindow::CShadowWindow(QWidget* pShadowWidget, QWidget *parent)
: QWidget(parent),
m_pShadowWidget(pShadowWidget),
m_iShadowSize(20),
m_shadowColor(0, 0, 0, 255),
m_fBlurRadius(20)
{
//设置窗口无边框
setWindowFlags(Qt::FramelessWindowHint);
//设置窗口背景透明
setAttribute(Qt::WA_TranslucentBackground, true);
InitConstruct();
}
CShadowWindow::~CShadowWindow()
{
}
void CShadowWindow::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);
//实例阴影shadow
QGraphicsDropShadowEffect *pShadow = new QGraphicsDropShadowEffect(this);
//设置阴影偏移距离
pShadow->setOffset(0, 0);
//设置阴影颜色
pShadow->setColor(m_shadowColor);
//设置阴影圆角
pShadow->setBlurRadius(m_fBlurRadius);
//给嵌套QWidget设置阴影
m_pShadowWidget->setGraphicsEffect(pShadow);
}
void CShadowWindow::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 CShadowWindow::GetShadowSize() const
{
return m_iShadowSize;
}
void CShadowWindow::SetShadowColor(const QColor& color)
{
if (color != m_shadowColor)
{
m_shadowColor = color;
auto pShadow = dynamic_cast<QGraphicsDropShadowEffect*>(m_pShadowWidget->graphicsEffect());
pShadow->setColor(m_shadowColor);
}
}
void CShadowWindow::SetShadowBlurRadius(qreal blurRadius)
{
if (qAbs(blurRadius-m_fBlurRadius)>1e-5)
{
m_fBlurRadius = blurRadius;
auto pShadow = dynamic_cast<QGraphicsDropShadowEffect*>(m_pShadowWidget->graphicsEffect());
pShadow->setBlurRadius(m_fBlurRadius);
}
}
void CShadowWindow::resizeEvent(QResizeEvent*)
{
const QSize sz = size();
m_pShadowWidget->setGeometry(m_iShadowSize, m_iShadowSize,
qAbs(sz.width() - m_iShadowSize * 2), qAbs(sz.height() - m_iShadowSize * 2));
}
CShadowWindow::Direction CShadowWindow::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 CShadowWindow::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 CShadowWindow::DragAndResizeWidget(CShadowWindow::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 CShadowWindow::mousePressEvent(QMouseEvent* pEvent)
{
if (Qt::LeftButton == pEvent->button())
{
m_ptPreGlobal = pEvent->globalPos();
m_Direction = CalcDirection(pEvent->pos());
SetMouseCursorStyle(m_Direction);
}
}
void CShadowWindow::mouseReleaseEvent(QMouseEvent* pEvent)
{
m_ptPreGlobal = QPoint();
setCursor(Qt::ArrowCursor);
}
void CShadowWindow::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();
}