Qt编写自定义控件:带阴影、圆角、可拉伸的弹窗

代码:

#ifndef SHADOW_WIDGET_H
#define SHADOW_WIDGET_H

#include <QWidget>

class Shadow_Widget : public QWidget
{
    Q_OBJECT

public:
    Shadow_Widget(QWidget *parent = nullptr);
    ~Shadow_Widget();
    void setCenterWidgetLayout(QLayout * layout);

protected:
    void mouseMoveEvent(QMouseEvent *event)override;
    void mousePressEvent(QMouseEvent *event)override;
    void mouseReleaseEvent(QMouseEvent *event)override;

private:
    void setLayout(QLayout * layout);
    void updatePaddingRect();
    QWidget * widget;
    enum class pressType
    {
        NoPressed,                 //未按下
        PressedRight,              //鼠标按下右侧
        PressedBottom,             //鼠标按下下侧
        PressedRightBottom,        //鼠标按下右下侧
        PressedButNotInPadding     //按下但没在右、下、右下边缘
    };
    pressType mousePressType{pressType::NoPressed};
    int padding;                    //边距
    bool moveEnable = true;         //可移动
    bool resizeEnable = true;        //可拉伸

    int rectX, rectY, rectW, rectH; //窗体坐标+宽高
    QPoint lastPos;

    QRect rectRight;
    QRect rectBottom;
    QRect rectRightBottom;
};
#endif // SHADOW_WIDGET_H
#include "shadow_widget.h"
#include <QVBoxLayout>
#include <QGraphicsDropShadowEffect>
#include <QEvent>
#include <QMouseEvent>

Shadow_Widget::Shadow_Widget(QWidget *parent)
    : QWidget(parent)
{
    padding = 15;
    moveEnable = true;
    resizeEnable = true;

    widget = new QWidget;
    widget->setObjectName("centerWidget");
    widget->setStyleSheet("QWidget#centerWidget{background-color:#FFFFFF;border-radius:15px;}");

    QVBoxLayout *lay_bg = new QVBoxLayout;
    lay_bg->addWidget(widget);

    setAttribute(Qt::WA_TranslucentBackground, true);
    setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);

    QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this);
    shadow->setOffset(0, 0);
    shadow->setColor(QColor("#444444"));
    shadow->setBlurRadius(padding);
    widget->setGraphicsEffect(shadow);
    lay_bg->setContentsMargins(padding,padding,padding,padding);

    setLayout(lay_bg);
    setMouseTracking(true);
    widget->setMouseTracking(true);
}

Shadow_Widget::~Shadow_Widget()
{
}

void Shadow_Widget::mouseMoveEvent(QMouseEvent *event)
{
    QPoint point = event->pos();
    if (resizeEnable)
    {
        updatePaddingRect();
        if (rectRight.contains(point))
        {
            setCursor(Qt::SizeHorCursor);
        }
        else if (rectBottom.contains(point))
        {
            setCursor(Qt::SizeVerCursor);
        }
        else if (rectRightBottom.contains(point))
        {
            setCursor(Qt::SizeFDiagCursor);
        }
        else
        {
            setCursor(Qt::ArrowCursor);
        }
    }

    //根据当前鼠标位置,计算XY轴移动了多少
    int offsetX = point.x() - lastPos.x();
    int offsetY = point.y() - lastPos.y();

    //根据按下处的位置判断是否是移动控件还是拉伸控件
    if (moveEnable)
    {
        if (mousePressType == pressType::PressedButNotInPadding)
        {
            move(x() + offsetX, y() + offsetY);
        }
    }

    if (resizeEnable)
    {
        if (mousePressType == pressType::PressedRight)
        {
            setGeometry(rectX, rectY, rectW + offsetX, rectH);
        }
        else if (mousePressType == pressType::PressedBottom)
        {
            setGeometry(rectX, rectY, rectW, rectH + offsetY);
        }
        else if (mousePressType == pressType::PressedRightBottom)
        {
            int resizeW = rectW + offsetX;
            int resizeH = rectH + offsetY;
            setGeometry(x(), y(), resizeW, resizeH);
        }
        else
        {
        }
        updatePaddingRect();
    }

    QWidget::mouseMoveEvent(event);
}

void Shadow_Widget::mousePressEvent(QMouseEvent *event)
{
    rectX = x();
    rectY = y();
    rectW = width();
    rectH = height();
    lastPos = event->pos();

    if (rectRight.contains(lastPos))
    {
        mousePressType = pressType::PressedRight;
    }
    else if (rectBottom.contains(lastPos))
    {
        mousePressType = pressType::PressedBottom;
    }
    else if (rectRightBottom.contains(lastPos))
    {
        mousePressType = pressType::PressedRightBottom;
    }
    else
    {
        mousePressType = pressType::PressedButNotInPadding;
    }
    QWidget::mousePressEvent(event);
}

void Shadow_Widget::mouseReleaseEvent(QMouseEvent *event)
{
    mousePressType = pressType::NoPressed;
    setCursor(Qt::ArrowCursor);
    updatePaddingRect();
    QWidget::mouseReleaseEvent(event);
}

void Shadow_Widget::setLayout(QLayout *layout)
{
    QWidget::setLayout(layout);
}

void Shadow_Widget::setCenterWidgetLayout(QLayout *layout)
{
    if(widget->layout())
        return;

    int left{0},top{0},right{0},bottom{0};
    layout->getContentsMargins(&left, &top, &right, &bottom);
    layout->setContentsMargins(std::max(left,padding),std::max(top,padding),
                               std::max(right,padding),std::max(bottom,padding));
    widget->setLayout(layout);
}

void Shadow_Widget::updatePaddingRect()
{
    int width = this->width();
    int height = this->height();
    int padding = 20;

    rectRight = QRect(width - padding, padding, padding, height - padding * 2);
    rectBottom = QRect(padding, height - padding, width - padding * 2, padding);
    rectRightBottom = QRect(width - padding, height - padding, padding, padding);
}

使用:

#include "shadow_widget.h"
#include <QApplication>
#include <QGridLayout>
#include <QPushButton>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGridLayout * gl = new QGridLayout;
    for(int i = 0;i< 5;++i)
    {
        for(int j = 0;j < 5;++j)
        {
            gl->addWidget(new QPushButton("测试"),i,j);
        }
    }
    Shadow_Widget w;
    w.setCenterWidgetLayout(gl);
    w.show();
    w.resize(600,600);
    return a.exec();
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值