Qt实现无边框带阴影边框可移动的窗口

如何实现无边框带阴影的一个窗口呢,下面的代码可以参考下,适当的调整下自己的radiu来实现需要的效果,代码有注释

  • CcShadowWidget.h
#ifndef CCSHADOWWIDGET_H
#define CCSHADOWWIDGET_H

#include <QWidget>
#include <QVector>

class CcShadowWidget : public QWidget
{
    Q_OBJECT

public:
    explicit CcShadowWidget(QWidget *parent = nullptr);
    ~CcShadowWidget();

protected:
    virtual void paintEvent(QPaintEvent* event)override;

private:
    void initWidget();

private:
    int m_alphaValue = 30;//透明度
    int m_radius = 6; //默认窗口的圆角半径
    QVector<int> m_blurValue;//阴影渐变的颜色
    QColor m_shadowColor = QColor("#65666e");//阴影的颜色
    QColor m_backgroundColor = Qt::white;//窗口的背景颜色
};

#endif // CCSHADOWWIDGET_H
  • CcShadowWidget.cpp
#include "CcShadowWidget.h"
#include <qmath.h>
#include <QPainter>

CcShadowWidget::CcShadowWidget(QWidget *parent)
    :QWidget(parent)
{
    initWidget();
}

CcShadowWidget::~CcShadowWidget()
{

}

void CcShadowWidget::initWidget()
{
    //TODO: 设置默认窗口大小
    resize(400,400);

    //TODO: 设置窗口无边框/背景透明属性
    setWindowFlags(windowFlags() | Qt::FramelessWindowHint);//无边框的窗口
    setAttribute(Qt::WA_TranslucentBackground,true);//实现圆角的无边框窗口必须设置的属性

    //TODO: 初始化阴影的渐变值
    qreal factor = m_alphaValue / m_radius;
    for (int i = 0; i < m_radius; i++)
    {
        int level = (int)(m_alphaValue - qSqrt(i) * factor + 0.5);
        m_blurValue.push_back(qMax<int>(0, level - 2));
    }
}

void CcShadowWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    //TODO: 先填充背景,原来是透明的,用背景颜色进行填充
    QPainterPath path;
    path.setFillRule(Qt::WindingFill);
    path.addRoundedRect(m_radius, m_radius, width() - m_radius * 2,
                        height() - m_radius * 2, m_radius, m_radius);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.fillPath(path, QBrush(m_backgroundColor));

    //TODO: 再绘制圆角矩形path,利用渐变的颜色。
    auto color = m_shadowColor;
    for (int i = 0; i < m_radius; i++)
    {
        QPainterPath path;
        path.setFillRule(Qt::WindingFill);
        path.addRoundedRect(m_radius - i, m_radius - i, width() - (m_radius - i) * 2,
                            height() - (m_radius - i) * 2, m_radius, m_radius);

        int alpha = 0;
        if (i < m_blurValue.size())
        {
            alpha = m_blurValue[i];
        }
        color.setAlpha(alpha);
        painter.setPen(color);
        painter.drawPath(path);
    }
}
  • 结果
  • 在这里插入图片描述

现在鼠标选中拖动是不能移动,其实挺简单的,只需要实现加上鼠标按下(QMousePressEvent)、鼠标移动(QMouseMoveEvent)、鼠标松开(QMouseReleaseEvent)这几个事件就可以

  • CcShadowWidget
#ifndef CCSHADOWWIDGET_H
#define CCSHADOWWIDGET_H

#include <QWidget>
#include <QVector>

class CcShadowWidget : public QWidget
{
    Q_OBJECT

public:
    explicit CcShadowWidget(QWidget *parent = nullptr);
    ~CcShadowWidget();

protected:
    virtual void paintEvent(QPaintEvent* event)override;
    //为了能够让窗口移动,加上鼠标按下,松开,移动的事件处理
    virtual void mouseMoveEvent(QMouseEvent *event) override;
    virtual void mousePressEvent(QMouseEvent *event) override;
    virtual void mouseReleaseEvent(QMouseEvent *event) override;
private:
    void initWidget();

private:
    int m_alphaValue = 30;//透明度
    int m_radius = 6; //默认窗口的圆角半径
    QVector<int> m_blurValue;//阴影渐变的颜色
    QColor m_shadowColor = QColor("#65666e");//阴影的颜色
    QColor m_backgroundColor = Qt::white;//窗口的背景颜色

    //能够移动窗口的属性
    bool m_lefted = false;
    QPoint m_leftPoint;
};

#endif // CCSHADOWWIDGET_H
  • CcShdowWidget.cpp
#include "CcShadowWidget.h"
#include <qmath.h>
#include <QPainter>
#include <QMouseEvent>

CcShadowWidget::CcShadowWidget(QWidget *parent)
    :QWidget(parent)
{
    initWidget();
}

CcShadowWidget::~CcShadowWidget()
{

}

void CcShadowWidget::initWidget()
{
    //TODO: 设置默认窗口大小
    resize(400,400);

    //TODO: 设置窗口无边框/背景透明属性
    setWindowFlags(windowFlags() | Qt::FramelessWindowHint);//无边框的窗口
    setAttribute(Qt::WA_TranslucentBackground,true);//实现圆角的无边框窗口必须设置的属性

    //TODO: 初始化阴影的渐变值
    qreal factor = m_alphaValue / m_radius;
    for (int i = 0; i < m_radius; i++)
    {
        int level = (int)(m_alphaValue - qSqrt(i) * factor + 0.5);
        m_blurValue.push_back(qMax<int>(0, level - 2));
    }
}

void CcShadowWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    //TODO: 先填充背景,原来是透明的,用背景颜色进行填充
    QPainterPath path;
    path.setFillRule(Qt::WindingFill);
    path.addRoundedRect(m_radius, m_radius, width() - m_radius * 2,
                        height() - m_radius * 2, m_radius, m_radius);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.fillPath(path, QBrush(m_backgroundColor));

    //TODO: 再绘制圆角矩形path,利用渐变的颜色。
    auto color = m_shadowColor;
    for (int i = 0; i < m_radius; i++)
    {
        QPainterPath path;
        path.setFillRule(Qt::WindingFill);
        path.addRoundedRect(m_radius - i, m_radius - i, width() - (m_radius - i) * 2,
                            height() - (m_radius - i) * 2, m_radius, m_radius);

        int alpha = 0;
        if (i < m_blurValue.size())
        {
            alpha = m_blurValue[i];
        }
        color.setAlpha(alpha);
        painter.setPen(color);
        painter.drawPath(path);
    }
}

void CcShadowWidget::mouseMoveEvent(QMouseEvent *event)
{
    if (m_lefted)
    {
        //TODO: 鼠标移动时计算 (当前鼠标的位置- 按下鼠标位置的差= 窗口移动的距离)
        QPoint offset = event->pos() - m_leftPoint;
        move(offset + pos());
    }
}

void CcShadowWidget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        //TODO: 记录鼠标按下时的位置(QPoint)
        m_lefted = true;
        m_leftPoint = event->pos();
    }
}

void CcShadowWidget::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        //TODO: 鼠标释放时重置下记录的数据
        m_lefted = false;
        m_leftPoint.setX(0);
        m_leftPoint.setY(0);
    }
}
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值