Qt实现阴影边框,可拖动,可缩放窗口(一)

通过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();
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值