一、framelesshelper.h
- #ifndef FRAMELESSHELPER_H
- #define FRAMELESSHELPER_H
- #include <QObject>
- #include <QApplication>
- #include <QHoverEvent>
- #include <QMouseEvent>
- #include <QRect>
- #include <QRubberBand>
- #include <QScopedPointer>
- #include <QScreen>
- class QWidget;
- class FramelessHelperPrivate;
- class FramelessHelper : public QObject {
-     Q_OBJECT
- public:
-     explicit FramelessHelper(QObject* parent = nullptr);
-     ~FramelessHelper();
-     // 激活窗体
-     void activateOn(QWidget* topLevelWidget);
-     // 移除窗体
-     void removeFrom(QWidget* topLevelWidget);
-     // 设置窗体移动
-     void setWidgetMovable(bool movable);
-     // 设置窗体缩放
-     void setWidgetResizable(bool resizable);
-     // 设置橡皮筋移动
-     void setRubberBandOnMove(bool movable);
-     // 设置橡皮筋缩放
-     void setRubberBandOnResize(bool resizable);
-     // 设置边框的宽度
-     void setBorderWidth(int width);
-     // 设置标题栏高度
-     void setTitleHeight(int height);
-     bool widgetResizable();
-     bool widgetMovable();
-     bool rubberBandOnMove();
-     bool rubberBandOnResisze();
-     int borderWidth();
-     int titleHeight();
- protected:
-     // 事件过滤,进行移动、缩放等
-     virtual bool eventFilter(QObject* obj, QEvent* event);
- private:
-     FramelessHelperPrivate* d;
- };
- #endif // FRAMELESS_HELPER_H
二、framelesshelper.cpp
- #include "framelesshelper.h"
- class WidgetData;
- /*****
-  * FramelessHelperPrivate
-  * 存储界面对应的数据集合,以及是否可移动、可缩放属性
- *****/
- class FramelessHelperPrivate {
- public:
-     QHash<QWidget*, WidgetData*> m_widgetDataHash;
-     bool m_bWidgetMovable : true;
-     bool m_bWidgetResizable : true;
-     bool m_bRubberBandOnResize : true;
-     bool m_bRubberBandOnMove : true;
- };
- /*****
-  * CursorPosCalculator
-  * 计算鼠标是否位于左、上、右、下、左上角、左下角、右上角、右下角
- *****/
- class CursorPosCalculator {
- public:
-     explicit CursorPosCalculator();
-     void reset();
-     void recalculate(const QPoint& globalMousePos, const QRect& frameRect);
- public:
-     bool m_bOnEdges : true;
-     bool m_bOnLeftEdge : true;
-     bool m_bOnRightEdge : true;
-     bool m_bOnTopEdge : true;
-     bool m_bOnBottomEdge : true;
-     bool m_bOnTopLeftEdge : true;
-     bool m_bOnBottomLeftEdge : true;
-     bool m_bOnTopRightEdge : true;
-     bool m_bOnBottomRightEdge : true;
-     static int m_nBorderWidth;
-     static int m_nTitleHeight;
- };
- int CursorPosCalculator::m_nBorderWidth = 5;
- int CursorPosCalculator::m_nTitleHeight = 30;
- /***** CursorPosCalculator *****/
- CursorPosCalculator::CursorPosCalculator()
- {
-     reset();
- }
- void CursorPosCalculator::reset()
- {
-     m_bOnEdges = false;
-     m_bOnLeftEdge = false;
-     m_bOnRightEdge = false;
-     m_bOnTopEdge = false;
-     m_bOnBottomEdge = false;
-     m_bOnTopLeftEdge = false;
-     m_bOnBottomLeftEdge = false;
-     m_bOnTopRightEdge = false;
-     m_bOnBottomRightEdge = false;
- }
- void CursorPosCalculator::recalculate(const QPoint& gMousePos, const QRect& frameRect)
- {
-     int globalMouseX = gMousePos.x();
-     int globalMouseY = gMousePos.y();
-     int frameX = frameRect.x();
-     int frameY = frameRect.y();
-     int frameWidth = frameRect.width();
-     int frameHeight = frameRect.height();
-     m_bOnLeftEdge = (globalMouseX >= frameX && globalMouseX <= frameX + m_nBorderWidth);
-     m_bOnRightEdge = (globalMouseX >= frameX + frameWidth - m_nBorderWidth && globalMouseX <= frameX + frameWidth);
-     m_bOnTopEdge = (globalMouseY >= frameY && globalMouseY <= frameY + m_nBorderWidth);
-     m_bOnBottomEdge = (globalMouseY >= frameY + frameHeight - m_nBorderWidth && globalMouseY <= frameY + frameHeight);
-     m_bOnTopLeftEdge = m_bOnTopEdge && m_bOnLeftEdge;
-     m_bOnBottomLeftEdge = m_bOnBottomEdge && m_bOnLeftEdge;
-     m_bOnTopRightEdge = m_bOnTopEdge && m_bOnRightEdge;
-     m_bOnBottomRightEdge = m_bOnBottomEdge && m_bOnRightEdge;
-     m_bOnEdges = m_bOnLeftEdge || m_bOnRightEdge || m_bOnTopEdge || m_bOnBottomEdge;
- }
- /*****
-  * WidgetData
-  * 更新鼠标样式、移动窗体、缩放窗体
- *****/
- class WidgetData {
- public:
-     explicit WidgetData(FramelessHelperPrivate* d, QWidget* pTopLevelWidget);
-     ~WidgetData();
-     QWidget* widget();
- public:
-     void handleWidgetEvent(QEvent* event); // 处理鼠标事件-划过、按下、释放、移动
-     void updateRubberBandStatus(); // 更新橡皮筋状态
- private:
-     void updateCursorShape(const QPoint& gMousePos); // 更新鼠标样式
-     void resizeWidget(const QPoint& gMousePos); // 重置窗体大小
-     void moveWidget(const QPoint& gMousePos); // 移动窗体
- protected:
-     void handleMousePressEvent(QMouseEvent* event); // 处理鼠标按下
-     void handleMouseReleaseEvent(QMouseEvent* event); // 处理鼠标释放
-     void handleMouseMoveEvent(QMouseEvent* event); // 处理鼠标移动
-     //void handleLeaveEvent(QEvent *event);// 处理鼠标离开
-     void handleHoverMoveEvent(QHoverEvent* event); // 处理鼠标进入
-     void handleMouseButtonDblClickEvent(QMouseEvent* event); // 处理双击左键鼠标
- private:
-     FramelessHelperPrivate* d;
-     QRubberBand* m_pRubberBand;
-     QWidget* m_pWidget;
-     QPoint m_ptDragPos;
-     CursorPosCalculator m_pressedMousePos;
-     CursorPosCalculator m_moveMousePos;
-     bool m_bLeftButtonPressed;
-     bool m_bCursorShapeChanged;
-     bool m_bLeftButtonTitlePressed;
-     Qt::WindowFlags m_windowFlags;
- };
- /***** WidgetData *****/
- WidgetData::WidgetData(FramelessHelperPrivate* _d, QWidget* pTopLevelWidget)
- {
-     d = _d;
-     m_pWidget = pTopLevelWidget;
-     m_bLeftButtonPressed = false;
-     m_bCursorShapeChanged = false;
-     m_bLeftButtonTitlePressed = false;
-     m_pRubberBand = nullptr;
-     m_windowFlags = m_pWidget->windowFlags();
-     m_pWidget->setMouseTracking(true);
-     m_pWidget->setAttribute(Qt::WA_Hover, true);
-     updateRubberBandStatus();
- }
- WidgetData::~WidgetData()
- {
-     m_pWidget->setMouseTracking(false);
-     m_pWidget->setWindowFlags(m_windowFlags);
-     m_pWidget->setAttribute(Qt::WA_Hover, false);
-     delete m_pRubberBand;
-     m_pRubberBand = nullptr;
- }
- QWidget* WidgetData::widget()
- {
-     return m_pWidget;
- }
- void WidgetData::handleWidgetEvent(QEvent* event)
- {
-     switch (event->type()) {
-     case QEvent::MouseButtonPress:
-         handleMousePressEvent(static_cast<QMouseEvent*>(event));
-         break;
-     case QEvent::MouseButtonRelease:
-         handleMouseReleaseEvent(static_cast<QMouseEvent*>(event));
-         break;
-     case QEvent::MouseMove:
-         handleMouseMoveEvent(static_cast<QMouseEvent*>(event));
-         break;
-         //        case QEvent::Leave:
-         //            handleLeaveEvent(static_cast<QMouseEvent*>(event));
-         //            break;
-     case QEvent::HoverMove:
-         handleHoverMoveEvent(static_cast<QHoverEvent*>(event));
-         break;
-     case QEvent::MouseButtonDblClick:
-         handleMouseButtonDblClickEvent(static_cast<QMouseEvent*>(event));
-         break;
-     default:
-         break;
-     }
- }
- void WidgetData::updateRubberBandStatus()
- {
-     if (d->m_bRubberBandOnMove || d->m_bRubberBandOnResize) {
-         if (nullptr == m_pRubberBand)
-             m_pRubberBand = new QRubberBand(QRubberBand::Rectangle);
-     } else {
-         delete m_pRubberBand;
-         m_pRubberBand = nullptr;
-     }
- }
- void WidgetData::updateCursorShape(const QPoint& gMousePos)
- {
-     m_moveMousePos.recalculate(gMousePos, m_pWidget->frameGeometry());
-     if (m_moveMousePos.m_bOnTopLeftEdge || m_moveMousePos.m_bOnBottomRightEdge) {
-         m_pWidget->setCursor(Qt::SizeFDiagCursor);
-         m_bCursorShapeChanged = true;
-     } else if (m_moveMousePos.m_bOnTopRightEdge || m_moveMousePos.m_bOnBottomLeftEdge) {
-         m_pWidget->setCursor(Qt::SizeBDiagCursor);
-         m_bCursorShapeChanged = true;
-     } else if (m_moveMousePos.m_bOnLeftEdge || m_moveMousePos.m_bOnRightEdge) {
-         m_pWidget->setCursor(Qt::SizeHorCursor);
-         m_bCursorShapeChanged = true;
-     } else if (m_moveMousePos.m_bOnTopEdge || m_moveMousePos.m_bOnBottomEdge) {
-         m_pWidget->setCursor(Qt::SizeVerCursor);
-         m_bCursorShapeChanged = true;
-     } else {
-         if (m_bCursorShapeChanged) {
-             m_pWidget->unsetCursor();
-             m_bCursorShapeChanged = false;
-         }
-     }
- }
- void WidgetData::resizeWidget(const QPoint& gMousePos)
- {
-     QRect origRect;
-     if (d->m_bRubberBandOnResize)
-         origRect = m_pRubberBand->frameGeometry();
-     else
-         origRect = m_pWidget->frameGeometry();
-     int left = origRect.left();
-     int top = origRect.top();
-     int right = origRect.right();
-     int bottom = origRect.bottom();
-     origRect.getCoords(&left, &top, &right, &bottom);
-     int minWidth = m_pWidget->minimumWidth();
-     int minHeight = m_pWidget->minimumHeight();
-     if (m_pressedMousePos.m_bOnTopLeftEdge) {
-         left = gMousePos.x();
-         top = gMousePos.y();
-     } else if (m_pressedMousePos.m_bOnBottomLeftEdge) {
-         left = gMousePos.x();
-         bottom = gMousePos.y();
-     } else if (m_pressedMousePos.m_bOnTopRightEdge) {
-         right = gMousePos.x();
-         top = gMousePos.y();
-     } else if (m_pressedMousePos.m_bOnBottomRightEdge) {
-         right = gMousePos.x();
-         bottom = gMousePos.y();
-     } else if (m_pressedMousePos.m_bOnLeftEdge) {
-         left = gMousePos.x();
-     } else if (m_pressedMousePos.m_bOnRightEdge) {
-         right = gMousePos.x();
-     } else if (m_pressedMousePos.m_bOnTopEdge) {
-         top = gMousePos.y();
-     } else if (m_pressedMousePos.m_bOnBottomEdge) {
-         bottom = gMousePos.y();
-     }
-     QRect newRect(QPoint(left, top), QPoint(right, bottom));
-     if (newRect.isValid()) {
-         if (minWidth > newRect.width()) {
-             if (left != origRect.left())
-                 newRect.setLeft(origRect.left());
-             else
-                 newRect.setRight(origRect.right());
-         }
-         if (minHeight > newRect.height()) {
-             if (top != origRect.top())
-                 newRect.setTop(origRect.top());
-             else
-                 newRect.setBottom(origRect.bottom());
-         }
-         if (d->m_bRubberBandOnResize) {
-             m_pRubberBand->setGeometry(newRect);
-             m_pRubberBand->update();
-         } else {
-             m_pWidget->setGeometry(newRect);
-             m_pWidget->update();
-         }
-     }
- }
- void WidgetData::moveWidget(const QPoint& gMousePos)
- {
-     if (d->m_bRubberBandOnMove)
-         m_pRubberBand->move(gMousePos - m_ptDragPos);
-     else
-         m_pWidget->move(gMousePos - m_ptDragPos);
- }
- void WidgetData::handleMousePressEvent(QMouseEvent* event)
- {
-     if (event->button() == Qt::LeftButton) {
-         m_bLeftButtonPressed = true;
-         if (m_pWidget->isFullScreen() || m_pWidget->isMaximized() || !d->m_bWidgetResizable)
-             m_bLeftButtonTitlePressed = event->pos().y() <= m_moveMousePos.m_nTitleHeight;
-         else
-             m_bLeftButtonTitlePressed = event->pos().y() <= m_moveMousePos.m_nTitleHeight && event->pos().y() > m_moveMousePos.m_nBorderWidth;
-         QRect frameRect = m_pWidget->frameGeometry();
-         m_pressedMousePos.recalculate(event->globalPos(), frameRect);
-         m_ptDragPos = event->globalPos() - frameRect.topLeft();
-         if (d->m_bRubberBandOnMove && m_bLeftButtonTitlePressed) {
-             m_pRubberBand->setGeometry(frameRect);
-             m_pRubberBand->show();
-         } else if (m_pressedMousePos.m_bOnEdges) {
-             if (d->m_bRubberBandOnResize) {
-                 m_pRubberBand->setGeometry(frameRect);
-                 m_pRubberBand->show();
-             }
-         }
-     }
- }
- void WidgetData::handleMouseMoveEvent(QMouseEvent* event)
- {
-     if (m_pWidget->isFullScreen() || m_pWidget->isMaximized()) {
-         if (m_bCursorShapeChanged) {
-             m_pWidget->unsetCursor();
-         }
-         return;
-     }
-     if (m_bLeftButtonPressed) {
-         if (d->m_bWidgetMovable && m_bLeftButtonTitlePressed) {
-             moveWidget(event->globalPos());
-         } else if (d->m_bWidgetResizable && m_pressedMousePos.m_bOnEdges) {
-             resizeWidget(event->globalPos());
-         }
-     }
- }
- void WidgetData::handleMouseReleaseEvent(QMouseEvent* event)
- {
-     if (event->button() == Qt::LeftButton) {
-         m_bLeftButtonPressed = false;
-         m_bLeftButtonTitlePressed = false;
-         m_pressedMousePos.reset();
-         if (m_pRubberBand && m_pRubberBand->isVisible()) {
-             m_pRubberBand->hide();
-             m_pWidget->setGeometry(m_pRubberBand->geometry());
-         }
-     }
- }
- //void WidgetData::handleLeaveEvent(QEvent *event)
- //{
- //    Q_UNUSED(event)
- //    if (!m_bLeftButtonPressed)
- //    {
- //        //qDebug("handleLeaveEvent");
- //        m_pWidget->unsetCursor();
- //    }
- //}
- void WidgetData::handleHoverMoveEvent(QHoverEvent* event)
- {
-     if (m_pWidget->isFullScreen() || m_pWidget->isMaximized()) {
-         return;
-     }
-     if (d->m_bWidgetResizable) {
-         updateCursorShape(m_pWidget->mapToGlobal(event->pos()));
-     }
- }
- void WidgetData::handleMouseButtonDblClickEvent(QMouseEvent* event)
- {
-     if (event->button() == Qt::LeftButton && event->pos().y() < m_moveMousePos.m_nTitleHeight) {
-         if (d->m_bWidgetResizable) {
-             if (m_pWidget->isMaximized())
-                 m_pWidget->showNormal();
-             else
-                 m_pWidget->showMaximized();
-         }
-     }
- }
- /*****FramelessHelper*****/
- FramelessHelper::FramelessHelper(QObject* parent)
-     : QObject(parent)
-     , d(new FramelessHelperPrivate)
- {
-     d->m_bWidgetMovable = true;
-     d->m_bWidgetResizable = true;
-     d->m_bRubberBandOnResize = false;
-     d->m_bRubberBandOnMove = false;
- }
- FramelessHelper::~FramelessHelper()
- {
-     QList<QWidget*> keys = d->m_widgetDataHash.keys();
-     int size = keys.size();
-     for (int i = 0; i < size; ++i) {
-         delete d->m_widgetDataHash.take(keys[i]);
-     }
-     delete d;
- }
- bool FramelessHelper::eventFilter(QObject* obj, QEvent* event)
- {
-     switch (event->type()) {
-     case QEvent::MouseButtonDblClick:
-     case QEvent::MouseMove:
-     case QEvent::HoverMove:
-     case QEvent::MouseButtonPress:
-     case QEvent::MouseButtonRelease:
-     case QEvent::Leave: {
-         WidgetData* data = d->m_widgetDataHash.value(static_cast<QWidget*>(obj));
-         if (data) {
-             data->handleWidgetEvent(event);
-             return true;
-         }
-     } break;
-     default:
-         break;
-     }
-     return QObject::eventFilter(obj, event);
- }
- void FramelessHelper::activateOn(QWidget* topLevelWidget)
- {
-     if (!d->m_widgetDataHash.contains(topLevelWidget)) {
-         WidgetData* data = new WidgetData(d, topLevelWidget);
-         d->m_widgetDataHash.insert(topLevelWidget, data);
-         topLevelWidget->installEventFilter(this);
-     }
- }
- void FramelessHelper::removeFrom(QWidget* topLevelWidget)
- {
-     WidgetData* data = d->m_widgetDataHash.take(topLevelWidget);
-     if (data) {
-         topLevelWidget->removeEventFilter(this);
-         delete data;
-     }
- }
- void FramelessHelper::setRubberBandOnMove(bool movable)
- {
-     d->m_bRubberBandOnMove = movable;
-     QList<WidgetData*> list = d->m_widgetDataHash.values();
-     foreach (WidgetData* data, list) {
-         data->updateRubberBandStatus();
-     }
- }
- void FramelessHelper::setWidgetMovable(bool movable)
- {
-     d->m_bWidgetMovable = movable;
- }
- void FramelessHelper::setWidgetResizable(bool resizable)
- {
-     d->m_bWidgetResizable = resizable;
- }
- void FramelessHelper::setRubberBandOnResize(bool resizable)
- {
-     d->m_bRubberBandOnResize = resizable;
-     QList<WidgetData*> list = d->m_widgetDataHash.values();
-     foreach (WidgetData* data, list) {
-         data->updateRubberBandStatus();
-     }
- }
- void FramelessHelper::setBorderWidth(int width)
- {
-     if (width > 0) {
-         CursorPosCalculator::m_nBorderWidth = width;
-     }
- }
- void FramelessHelper::setTitleHeight(int height)
- {
-     if (height > 0) {
-         CursorPosCalculator::m_nTitleHeight = height;
-     }
- }
- bool FramelessHelper::widgetMovable()
- {
-     return d->m_bWidgetMovable;
- }
- bool FramelessHelper::widgetResizable()
- {
-     return d->m_bWidgetResizable;
- }
- bool FramelessHelper::rubberBandOnMove()
- {
-     return d->m_bRubberBandOnMove;
- }
- bool FramelessHelper::rubberBandOnResisze()
- {
-     return d->m_bRubberBandOnResize;
- }
- int FramelessHelper::borderWidth()
- {
-     return CursorPosCalculator::m_nBorderWidth;
- }
- int FramelessHelper::titleHeight()
- {
-     return CursorPosCalculator::m_nTitleHeight;
- }
三、使用
- // 窗口助手
- FramelessHelper* helper=new FramelessHelper(this);
- helper->activateOn(this);                           // 激活当前窗体
- helper->setTitleHeight(this->topBar->height());     // 设置窗体的标题栏高度
- helper->setWidgetMovable(true);                     // 设置窗体可移动
- helper->setWidgetResizable(true);                   // 设置窗体可缩放
- helper->setRubberBandOnMove(false);                 // 设置橡皮筋效果-可移动
- helper->setRubberBandOnResize(false);               // 设置橡皮筋效果-可缩放
四、去除窗口标题栏及背景透明
- setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
- setAttribute(Qt::WA_TranslucentBackground);
五、参考链接
https://developer.aliyun.com/article/24438