Qt源码分享(一)-- 圆角+阴影+可移动+大小可变

Qt源码分享(一)-- 圆角+阴影+可移动+大小可变

关注微信公众号在菜单栏获取源码

image

由于自己项目的需要,主界面需要实现圆角+阴影+可移动+拖拽可变大小。一看到这样的功能,立马就开始百度。结果百度了快一天都没有找到合适的,虽然能够实现圆角或者阴影的,但是实现的方式总觉得不太合适。最后还是高人赵哥把源码给我了,我又在网络上搜索了一番加上拖拽可变大小的功能。

好,我们先看下效果:
image

为了对原作者的尊重,头文件的作者我就保留了下。

拖拽可变大小我是参考这里的:https://www.cnblogs.com/xufeiyang/p/3313104.html

头文件的实现:

/*!
 * @file     mainwindow.h
 * @author   ZhaoYanbo
 * @date     2019-10-29
 * @details  ...
 * @version  v1.0.0
 */
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QDialog>
#include <QWidget>

class MainWindow : public QWidget
{
    Q_OBJECT

enum Direction{
    UP = 0,
    DOWN,
    LEFT,
    RIGHT,
    LEFTTOP,
    LEFTBOTTOM,
    RIGHTBOTTOM,
    RIGHTTOP,
    NONE
};

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

public:    
    void SetResizeable(bool isResize);
    bool IsResizeable() const;

    void SetRadius(bool radius);
    int GetRadius() const;

protected:
    void resizeEvent(QResizeEvent *) override;
    void paintEvent(QPaintEvent *) override;
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);

private:
    void region(const QPoint &cursorPoint);

    /*!
     * \brief 绘制带尖的图片
     * \param w      图片宽度
     * \param h      图片高度
     * \param tip_w  尖的宽度
     * \param tip_h  尖的高度
     * \param radius 矩形圆角半径
     * \param margin 边距
     * \return
     */
    QPixmap drawTip(const int w, const int h, const int tip_w, const int tip_h,
                    const int radius, const int margin);

private:
    QPixmap     m_pixmap;
    bool        mIsLeftPressDown;
    QPoint      mDragPosition;
    Direction   mDirec;
    bool        mResizeable;
    int         mRadius;

};

#endif // MAINWINDOW_H

实现的部分cpp文件:

#include "mainwindow.h"

#include <QGraphicsBlurEffect>
#include <QPainter>
#include <QResizeEvent>

static const int SHADOW_WIDTH = 16;

#define PADDING     18
#define PADDING_TOP 29

MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
    mIsLeftPressDown    = false;
    this->mResizeable   = true;
    this->mDirec        = NONE;
    this->mRadius       = 4;
    this->setMouseTracking(true);

    QGraphicsDropShadowEffect* pShadowEffect = new QGraphicsDropShadowEffect(this);
    pShadowEffect->setOffset(0, 0);
    pShadowEffect->setColor(Qt::lightGray);
    pShadowEffect->setBlurRadius(SHADOW_WIDTH);
    this->setGraphicsEffect(pShadowEffect);

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

MainWindow::~MainWindow()
{}

void MainWindow::SetResizeable(bool isResize)
{
    mResizeable = isResize;
}

bool MainWindow::IsResizeable() const
{
    return mResizeable;
}

void MainWindow::SetRadius(bool radius)
{
    mRadius = radius;
}

int MainWindow::GetRadius() const
{
    return mRadius;
}

void MainWindow::resizeEvent(QResizeEvent *e)
{
    const QSize s = e->size();
    int w = s.width();
    int h = s.height();
    if(w > 1 && h > 1) {
        m_pixmap = drawTip(w, h, 18, 12, mRadius, SHADOW_WIDTH);
    }
}

void MainWindow::paintEvent(QPaintEvent *)
{
    if(m_pixmap.isNull())
        return;

    QPainter p;
    p.begin(this);
    p.drawPixmap(this->rect(), m_pixmap);
    p.end();
}

void MainWindow::region(const QPoint &cursorGlobalPoint)
{
    QRect rect = this->rect();
    QPoint tl = mapToGlobal(rect.topLeft());
    QPoint rb = mapToGlobal(rect.bottomRight());
    int x = cursorGlobalPoint.x();
    int y = cursorGlobalPoint.y();

    if(tl.x() + PADDING_TOP >= x && tl.x() <= x && tl.y() + PADDING_TOP >= y && tl.y() <= y) {
        // 左上角
        mDirec = LEFTTOP;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    } else if(x >= rb.x() - PADDING && x <= rb.x() && y >= rb.y() - PADDING && y <= rb.y()) {
        // 右下角
        mDirec = RIGHTBOTTOM;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    } else if(x <= tl.x() + PADDING && x >= tl.x() && y >= rb.y() - PADDING && y <= rb.y()) {
        //左下角
        mDirec = LEFTBOTTOM;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    } else if(x <= tl.x() + PADDING && x >= tl.x()) {
        // 左边
        mDirec = LEFT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    } else if( x <= rb.x() && x >= rb.x() - PADDING) {
        // 右边
        mDirec = RIGHT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    }else if(y >= tl.y() && y <= tl.y() + PADDING_TOP){
        // 上边
        mDirec = UP;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    } else if(y <= rb.y() && y >= rb.y() - PADDING) {
        // 下边
        mDirec = DOWN;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    }else {
        // 默认
        mDirec = NONE;
        this->setCursor(QCursor(Qt::ArrowCursor));
    }
}

QPixmap MainWindow::drawTip(const int w, const int h, const int tip_w, const int tip_h, const int radius, const int margin)
{
    const int w2 = w - margin * 2 - radius * 2 - tip_w;

    QPainterPath path;

    // TODO 关注微信公众号:cpp手艺人

    return pixmap;
}

void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton) {
        mIsLeftPressDown = false;
        if(mDirec != NONE) {
            this->releaseMouse();
            this->setCursor(QCursor(Qt::ArrowCursor));
        }
    }
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    switch(event->button()) {
    case Qt::LeftButton:
        mIsLeftPressDown = true;
        if(mDirec != NONE) {
            this->mouseGrabber();
        } else {
            mDragPosition = event->globalPos() - this->frameGeometry().topLeft();
        }
        break;
    default:
        QWidget::mousePressEvent(event);
    }
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    QPoint gloPoint = event->globalPos();
    QRect rect = this->rect();
    QPoint tl = mapToGlobal(rect.topLeft());
    QPoint rb = mapToGlobal(rect.bottomRight());

    if(!mIsLeftPressDown) {
        if (mResizeable) {
            this->region(gloPoint);
        }
    } else {

        if(mDirec != NONE && mResizeable) {
            QRect rMove(tl, rb);

            switch(mDirec) {
            case LEFT:
                if(rb.x() - gloPoint.x() <= this->minimumWidth())
                    rMove.setX(tl.x() - SHADOW_WIDTH);
                else
                    rMove.setX(gloPoint.x() - SHADOW_WIDTH);
                break;
            case RIGHT:
                rMove.setWidth(gloPoint.x() - tl.x() + SHADOW_WIDTH);
                break;
            case UP:
                if(rb.y() - gloPoint.y() <= this->minimumHeight())
                    rMove.setY(tl.y() - PADDING_TOP);
                else
                    rMove.setY(gloPoint.y() - PADDING_TOP);
                break;
            case DOWN:
                rMove.setHeight(gloPoint.y() - tl.y() + SHADOW_WIDTH);
                break;
            case LEFTTOP:
                if(rb.x() - gloPoint.x() <= this->minimumWidth())
                    rMove.setX(tl.x() - PADDING);
                else
                    rMove.setX(gloPoint.x() - PADDING);
                if(rb.y() - gloPoint.y() <= this->minimumHeight())
                    rMove.setY(tl.y() - PADDING_TOP);
                else
                    rMove.setY(gloPoint.y() - PADDING_TOP);
                break;
            default:
                break;
            }
            this->setGeometry(rMove);
        } else {
            move(event->globalPos() - mDragPosition);
            event->accept();
        }
    }
    QWidget::mouseMoveEvent(event);
}

最后,如果这段源码帮助了你,节省了你的时间,请打赏下吧。我们不要5块,10块,只要1、2块,这段代码抱回家。让你早点下班,吃上热饭,保住头发。

大家拿到了源码,自己在封装封装,加入到自己的类库中,为以后的开发绝对节省不少时间。

关于赞赏,因为我跟赵哥说过了,大家打赏的都是他的。感谢大家对原创的支持。

关注微信公众号:菜单-》Qt源码分享

ent->globalPos() - mDragPosition);
event->accept();
}
}
QWidget::mouseMoveEvent(event);
}


最后,如果这段源码帮助了你,节省了你的时间,请打赏下吧。我们不要5块,10块,只要1、2块,这段代码抱回家。让你早点下班,吃上热饭,保住头发。

大家拿到了源码,自己在封装封装,加入到自己的类库中,为以后的开发绝对节省不少时间。

关于赞赏,因为我跟赵哥说过了,大家打赏的都是他的。感谢大家对原创的支持。

**关注微信公众号:菜单-》Qt源码分享**


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值