Qt QWidget 去除默认边框,可自由拉伸缩放

插件类,可使得Qt QWidget去除边框,可自由拉伸
/.h

#ifndef COMRESIZER_H
#define COMRESIZER_H
#include 
#include 
#include 
class COMResizer : public QObject
{
    Q_OBJECT
public:
    explicit COMResizer(QWidget *parent = nullptr);
    ~COMResizer();
    void attach();
    void detach();
    /**
     * @brief 设置移动触发热区
     * @param 0值或未设置表示包括全部区域
     */
    void setHotspot(const QSize & size);
    /*
     * 使能缩放窗口宽/高。
     * 默认只能移动,不能缩放。
     */
    void setResizable(bool width, bool height);
protected:
    bool eventFilter(QObject *obj, QEvent *event);

    void mouseEnterEvent(QEnterEvent *event);
    void mouseMoveEvent(QMouseEvent * event);
    void mousePressEvent(QMouseEvent * event);
    void mouseReleaseEvent(QMouseEvent * event);
    bool keyPressEvent(QKeyEvent *);

    void detectResizeMode(const QPoint & pos);
    void modifyResizeMode(uint mode);
    void moveParentWidget(const QPoint & global);
    void resizeParentWidget(const QPoint & global);
    QWidget *parentWidget() const;
    enum Mode {
        None = 0,
        Left = 1,
        Right = 2,
        Up = 3,
        LeftUp = Left + Up,
        RightUp = Right + Up,
        Down,
        LeftDown = Left + Down,
        RightDown = Right + Down
    };
    enum State {
        Idle, NormalMove, ResizeMove
    };
signals:
    void sigNormalWidget(bool bNormal);//拖动标题栏,窗体放缩
public slots:

private:
private:
    uint    mMode;
    State   mState;

    QSize   mHotspot;

    QRect   mBorder;
    bool    mResizable;

    QPoint  mSavedPos;
    QRect   mSavedRect;
    bool mbNeedRelocate;//true:窗口需要重定位
};

#endif // COMRESIZER_H

实现cpp

#include "COMResizer.h"
#include
#include

#define  BORDER_WIDTH  10
COMResizer::COMResizer(QWidget *parent) :
    QObject(parent),
    mMode(None),
    mState(Idle),
    mResizable(false),
    mbNeedRelocate(false)
{
    parent->setWindowFlags(parent->windowFlags()
                           |Qt::WindowSystemMenuHint
                           |Qt::FramelessWindowHint
                           |Qt::WindowMinMaxButtonsHint);

    attach();

   // connect(Mask4WinMax::getInstance(),&Mask4WinMax::sigNormalWidget, this, &COMResizer::sigNormalWidget);
    mHotspot = QSize(0, 30);//使窗体只有标题栏可以选中拖动


}

COMResizer::~COMResizer()
{

}

void COMResizer::attach()
{
    QWidget *parent = parentWidget();
    if (!parent->hasMouseTracking())
    {
        parent->setMouseTracking(true);
        parent->installEventFilter(this);

        // 状态复位
        mState = Idle;
        modifyResizeMode(None);
    }
}


void COMResizer::detach()
{
    QWidget *parent = parentWidget();
    if (parent->hasMouseTracking())
    {
        parent->setMouseTracking(false);
        parent->removeEventFilter(this);
    }
}

void COMResizer::setHotspot(const QSize &size)
{
    mHotspot = size;
}

void COMResizer::setResizable(bool width, bool height)
{
    int x = width ? BORDER_WIDTH : 0;
    int y = height ? BORDER_WIDTH : 0;

    mBorder.setLeft(x);
    mBorder.setRight(x);
    mBorder.setTop(y);
    mBorder.setBottom(y);

    mResizable = (width || height);
}

bool COMResizer::eventFilter(QObject *obj, QEvent *event)
{
    if (obj == parent())
    {
        switch(event->type())
        {
        case QEvent::Enter:
            mouseEnterEvent((QEnterEvent*)event);
            break;

        case QEvent::MouseButtonPress:
            mousePressEvent((QMouseEvent*)event);
            break;

        case QEvent::MouseButtonRelease:
            mouseReleaseEvent((QMouseEvent*)event);
            break;

        case QEvent::MouseMove:
            mouseMoveEvent((QMouseEvent*)event);
            break;

        case QEvent::KeyPress:
            return keyPressEvent(dynamic_cast<QKeyEvent*>(event));
        }

    }
    return false;
}

bool COMResizer::keyPressEvent(QKeyEvent *event)
{
    if(Qt::Key_Enter == event->key() || Qt::Key_Return == event->key())
    {
        event->ignore();
        return true;
    }

    return false;
}

void COMResizer::mouseEnterEvent(QEnterEvent *event)
{
    detectResizeMode(event->pos());
}

void COMResizer::mouseMoveEvent(QMouseEvent *event)
{
    if (mState == Idle)
    {
        detectResizeMode(event->pos());
    }
    else if (mState == NormalMove)
    {
        if(parentWidget()->isMaximized())
        {
            parentWidget()->showNormal();
            emit sigNormalWidget(true);

            mbNeedRelocate = true;
        }
        else
        {
            if(mbNeedRelocate)
            {
                //计算对话框重定位后的位置
                int newWidth = parentWidget()->geometry().width();
                int newHeight = parentWidget()->geometry().height();
                int newX = event->globalPos().x() -
                        (int)(((float)mSavedPos.x()-mSavedRect.left())/mSavedRect.width() * newWidth);
                int newY = event->globalPos().y() -
                        (int)(((float)mSavedPos.y()-mSavedRect.top())/mSavedRect.height() * newHeight);
                QRect rcNew = QRect(newX,newY,newWidth, newHeight);
                parentWidget()->setGeometry(rcNew);

                mSavedPos = event->globalPos();
                mSavedRect = rcNew;

                mbNeedRelocate = false;
            }
            else
            {
                moveParentWidget(event->globalPos());
            //	Mask4WinMax::getInstance()->SetBuddyWidget(parentWidget());//设置放缩时的遮罩
            }
        }
    }
    else if (mState == ResizeMove)
    {
        resizeParentWidget(event->globalPos());
    }
}

void COMResizer::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && mState == Idle)
    {
        if (mMode != None)
        {
            mState = ResizeMove;
        }
        else
        {
            // 不在热区,不能移动
            QPoint pos = event->pos();
            if (mHotspot.width() > 0 && pos.x() > mHotspot.width())
            {
                return;
            }
            if (mHotspot.height() > 0 && pos.y() > mHotspot.height())
            {
                return;
            }

            mState = NormalMove;
        }

        mSavedPos = event->globalPos();
        mSavedRect = parentWidget()->geometry();
    }
}

void COMResizer::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        mState = Idle;
        modifyResizeMode(None);
    }
}

void COMResizer::detectResizeMode(const QPoint &pos)
{
    if (!mResizable)
    {
        return;
    }

    uint mode = None;

    QRect rect = parentWidget()->rect();
    if (rect.contains(pos))
    {
        if (pos.x() < mBorder.left())
        {
            mode = Left;
        }
        else if (pos.x() + mBorder.right() > rect.right())
        {
            mode = Right;
        }

        if (pos.y() < mBorder.top())
        {
            mode += Up;
        }
        else if (pos.y() + mBorder.bottom() > rect.bottom())
        {
            mode += Down;
        }
    }

    modifyResizeMode(mode);
}

void COMResizer::modifyResizeMode(uint mode)
{
    if (mode == mMode)
    {
        // 拉伸区未变化
        return;
    }

    if (mMode == None)
    {
        // 首次进入拉伸区,持续接收鼠标消息
        parentWidget()->grabMouse();
    }

    Qt::CursorShape shape = Qt::ArrowCursor;
    if (mode == None)
    {
        // 离开拉伸区
        parentWidget()->releaseMouse();
    }
    else
    {
        switch(mode)
        {
        case Left:
        case Right:
            shape = Qt::SizeHorCursor;
            break;

        case Up:
        case Down:
            shape = Qt::SizeVerCursor;
            break;

        case LeftUp:
        case RightDown:
            shape = Qt::SizeFDiagCursor;
            break;

        case RightUp:
        case LeftDown:
            shape = Qt::SizeBDiagCursor;
            break;

        default:
            break;
        }
    }

    mMode = mode;
    parentWidget()->setCursor(QCursor(shape));
}

inline void COMResizer::moveParentWidget(const QPoint &global)
{
    QPoint pos = mSavedRect.topLeft()
            + global - mSavedPos;

    parentWidget()->move(pos);
}

void COMResizer::resizeParentWidget(const QPoint &global)
{
    // 拉伸移动
    QRect rect = mSavedRect;
    QPoint offset = global - mSavedPos;

    switch (mMode)
    {
    case Left:
        rect.setLeft(rect.left() + offset.x());
        break;

    case Right:
        rect.setRight(rect.right() + offset.x());
        break;

    case Up:
        rect.setTop(rect.top() + offset.y());
        break;

    case Down:
        rect.setBottom(rect.bottom() + offset.y());
        break;

    case LeftUp:
        rect.setTop(rect.top() + offset.y());
        rect.setLeft(rect.left() + offset.x());
        break;

    case RightUp:
        rect.setTop(rect.top() + offset.y());
        rect.setRight(rect.right() + offset.x());
        break;

    case LeftDown:
        rect.setLeft(rect.left() + offset.x());
        rect.setBottom(rect.bottom() + offset.y());
        break;

    case RightDown:
        rect.setRight(rect.right() + offset.x());
        rect.setBottom(rect.bottom() + offset.y());
        break;

    default:
        break;
    }
    parentWidget()->setGeometry(rect);
}

inline QWidget *COMResizer::parentWidget() const
{
    return static_cast<QWidget *>(QObject::parent());
}

使用方式
```cpp
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_resizer(new COMResizer(this))
{
    ui->setupUi(this);
    this->setStyleSheet("background: yellow");
    ui->label->setStyleSheet("background: blue");
    m_resizer->setResizable(true, true);

    connect(ui->pushButton, &QPushButton::clicked, this, [this]{close();});
    connect(ui->pushButton_2, &QPushButton::clicked, this, [this]{close();});
}

效果演示
Qt QWidget 去除默认边框,可自由拉伸缩放_第1张图片

你可能感兴趣的:(Qt/C++,qt)