qt无边框可移动窗口_Qt源码分享(一)-- 圆角+阴影+可移动+大小可变

099164efc6fc5c1ffdbca5e8a174e078.png

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

d9005c49bd00f738b231f75911446fb1.png

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

好,我们先看下效果:

66c6010ae6c9eca87faad601ce280566.gif

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

拖拽可变大小我是参考这里的: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);
}

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值