zoukankan      html  css  js  c++  java
  • Qt 无边框拖拽实现

    Qt 无边框拖拽实现

    头文件定义:

    class TDragProxy:public QObject
    {
    Q_OBJECT
    
    public:
        TDragProxy(QWidget* parent);
        ~TDragProxy();
    
    protected:
        enum WidgetRegion
        {
            Top = 0,
            TopRight,
            Right,
            RightBottom,
            Bottom,
            LeftBottom,
            Left,
            LeftTop,
            Inner,
            Unknown
        };
    
    public:
        void SetBorderWidth(int top, int right, int bottom, int left);//设置四周边框宽度
        void SetDragEnable(bool bEnable); //最大化无拖拽效果
    
    protected:
        virtual bool eventFilter(QObject* obj, QEvent* event);
    
        void MakeRegions();
        WidgetRegion HitTest(const QPoint& pos);
        void UpdateGeometry(int x, int y, int w, int h);
    
        //鼠标从边框快速移到窗体内子控件上,可能会造成鼠标样式未改变,这里使用计时器监控
        void StartCursorTimer();
        void StopCursorTimer();
    
    private:
        QWidget* m_proxyWidget; //代理的窗体
        int m_top,m_right,m_bottom,m_left; //四周宽度
        QRect m_regions[9]; //九宫格,对应9个区域
    
        QPoint m_originPosGlobal; //拖拽前鼠标位置
        QRect m_originGeo; //拖拽前窗体位置和大小
    
        bool m_mousePressed; //鼠标是否按下
        WidgetRegion m_regionPressed; //记录鼠标按下时所点击的区域
    
        int m_cursorTimerId;
    
        bool m_bDragEnable;
        bool m_bBorderMini; //边框为1时,处理四对角位置
    };

    CPP文件实现:

    TDragProxy::TDragProxy(QWidget *parent)
    :QObject((QObject*)parent)
    , m_bDragEnable(true)
    , m_bBorderMini(false)
    {
        m_proxyWidget = parent;
        m_top = m_right = m_bottom = m_left = 0;
    
        m_proxyWidget->setMouseTracking(true);
        m_proxyWidget->installEventFilter(this);    // 代理窗体事件
    
        m_mousePressed = false;
        m_regionPressed = Unknown;
    
        m_cursorTimerId = 0;
    }
    
    TDragProxy::~TDragProxy()
    {
    }
    
    void TDragProxy::SetBorderWidth(int top, int right, int bottom, int left)
    {
        m_top = top;
        m_right = right;
        m_bottom = bottom;
        m_left = left;
    
        if (m_top == 1 && m_right == 1 && m_bottom == 1 && m_left==1)
        {
            m_bBorderMini = true;
        }
    
        MakeRegions();
    }
    
    void TDragProxy::UpdateGeometry(int x, int y, int w, int h)
    {
        int minWidth = m_proxyWidget->minimumWidth();
        int minHeight = m_proxyWidget->minimumHeight();
        int maxWidth = m_proxyWidget->maximumWidth();
        int maxHeight = m_proxyWidget->maximumHeight();
    
        if (w < minWidth || w > maxWidth || h < minHeight || h > maxHeight)
        {
            return;
        }
    
        m_proxyWidget->setGeometry(x, y, w, h);
    }
    
    bool TDragProxy::eventFilter(QObject* obj, QEvent* event)
    {
        if (!m_bDragEnable)
        {
            return QObject::eventFilter(obj, event);
        }
    
        QEvent::Type eventType = event->type();
        if (eventType == QEvent::MouseMove)
        {
            QMouseEvent* mouseEvent = (QMouseEvent*)event;
            QPoint curPosLocal = mouseEvent->pos();
            TDragProxy::WidgetRegion regionType = HitTest(curPosLocal);
            QPoint curPosGlobal = m_proxyWidget->mapToGlobal(curPosLocal);
    
            if (!m_mousePressed)    // 鼠标未按下
            {
                switch (regionType)
                {
                    case Top:
                    case Bottom:
                        m_proxyWidget->setCursor(Qt::SizeVerCursor);
                        break;
                    case TopRight:
                    case LeftBottom:
                        m_proxyWidget->setCursor(Qt::SizeBDiagCursor);
                        break;
                    case Right:
                    case Left:
                        m_proxyWidget->setCursor(Qt::SizeHorCursor);
                        break;
                    case RightBottom:
                    case LeftTop:
                        m_proxyWidget->setCursor(Qt::SizeFDiagCursor);
                        break;
                    default:
                        m_proxyWidget->setCursor(Qt::ArrowCursor);
                        break;
                }
    
                StartCursorTimer();
            }
            else    // 鼠标已按下
            {
                QRect geo = m_proxyWidget->geometry();
    
                if (m_regionPressed == Inner)
                {
                    m_proxyWidget->move(m_originGeo.topLeft() + curPosGlobal - m_originPosGlobal);
                }
                else if (m_regionPressed == Top)
                {
                    int dY = curPosGlobal.y() - m_originPosGlobal.y();
                    UpdateGeometry(m_originGeo.x(), m_originGeo.y() + dY, m_originGeo.width(), m_originGeo.height() - dY);
                }
                else if (m_regionPressed == TopRight)
                {
                    QPoint dXY = curPosGlobal - m_originPosGlobal;
                    UpdateGeometry(m_originGeo.x(), m_originGeo.y() + dXY.y(), m_originGeo.width() + dXY.x(), m_originGeo.height() - dXY.y());
                }
                else if (m_regionPressed == Right)
                {
                    int dX = curPosGlobal.x() - m_originPosGlobal.x();
                    UpdateGeometry(m_originGeo.x(), m_originGeo.y(), m_originGeo.width() + dX, m_originGeo.height());
                }
                else if (m_regionPressed == RightBottom)
                {
                    QPoint dXY = curPosGlobal - m_originPosGlobal;
                    UpdateGeometry(m_originGeo.x(), m_originGeo.y(), m_originGeo.width() + dXY.x(), m_originGeo.height() + dXY.y());
                }
                else if (m_regionPressed == Bottom)
                {
                    int dY = curPosGlobal.y() - m_originPosGlobal.y();
                    UpdateGeometry(m_originGeo.x(), m_originGeo.y(), m_originGeo.width(), m_originGeo.height() + dY);
                }
                else if (m_regionPressed == LeftBottom)
                {
                    QPoint dXY = curPosGlobal - m_originPosGlobal;
                    UpdateGeometry(m_originGeo.x() + dXY.x(), m_originGeo.y(), m_originGeo.width() - dXY.x(), m_originGeo.height() + dXY.y());
                }
                else if (m_regionPressed == Left)
                {
                    int dX = curPosGlobal.x() - m_originPosGlobal.x();
                    UpdateGeometry(m_originGeo.x() + dX, m_originGeo.y(), m_originGeo.width() - dX, m_originGeo.height());
                }
                else if (m_regionPressed == LeftTop)
                {
                    QPoint dXY = curPosGlobal - m_originPosGlobal;
                    UpdateGeometry(m_originGeo.x() + dXY.x(), m_originGeo.y() + dXY.y(), m_originGeo.width() - dXY.x(), m_originGeo.height() - dXY.y());
                }
            }
        }
        else if (eventType == QEvent::MouseButtonPress)
        {
            QMouseEvent* mouseEvent = (QMouseEvent*)event;
            if (mouseEvent->button() == Qt::LeftButton)
            {
                m_mousePressed = true;
    
                QPoint curPos = mouseEvent->pos();
                m_regionPressed = HitTest(curPos);
    
                m_originPosGlobal = m_proxyWidget->mapToGlobal(curPos);
                m_originGeo = m_proxyWidget->geometry();
    
                StopCursorTimer();
            }
        }
        else if (eventType == QEvent::MouseButtonRelease)
        {
            m_mousePressed = false;
            m_regionPressed = Unknown;
    
            m_proxyWidget->setCursor(Qt::ArrowCursor);
        }
        else if (eventType == QEvent::Resize)
        {
            MakeRegions();
        }
        else if (eventType == QEvent::Leave)
        {
            m_proxyWidget->setCursor(Qt::ArrowCursor);
            StopCursorTimer();
        }
        else if (eventType == QEvent::Timer)
        {
            QTimerEvent* timerEvent = (QTimerEvent*)event;
            if (timerEvent->timerId() == m_cursorTimerId)
            {
                if (m_regions[Inner].contains(m_proxyWidget->mapFromGlobal(QCursor::pos())))
                {
                    m_proxyWidget->setCursor(Qt::ArrowCursor);
                    StopCursorTimer();
                }
            }
        }
        return QObject::eventFilter(obj, event);
    }
    
    void TDragProxy::StartCursorTimer()
    {
        StopCursorTimer();
        m_cursorTimerId = m_proxyWidget->startTimer(50);
    }
    
    void TDragProxy::StopCursorTimer()
    {
        if (m_cursorTimerId != 0)
        {
            m_proxyWidget->killTimer(m_cursorTimerId);
            m_cursorTimerId = 0;
        }
    }
    
    void TDragProxy::MakeRegions()
    {
        int width = m_proxyWidget->width();
        int height = m_proxyWidget->height();
    
        if (m_bBorderMini)
        {
            m_regions[Top] = QRect(2, 0, width - 4, 1);
            m_regions[TopRight] = QRect(width - 2, 0, 2, 2);
            m_regions[Right] = QRect(width - 1, 2, 1, height - 4);
            m_regions[RightBottom] = QRect(width - 2, height - 2, 2, 2);
            m_regions[Bottom] = QRect(2, height - 1, width - 4, 1);
            m_regions[LeftBottom] = QRect(0, height - 2, 2, 2);
            m_regions[Left] = QRect(0, 2, 1, height - 4);
            m_regions[LeftTop] = QRect(0, 0, 2, 2); 
            m_regions[Inner] = QRect(2, 2, width - 4, height - 4);
        }
        else
        {
            m_regions[Top] = QRect(m_left, 0, width - m_left - m_right, m_top);
            m_regions[TopRight] = QRect(width - m_right, 0, m_right, m_top);
            m_regions[Right] = QRect(width - m_right, m_top, m_right, height - m_top - m_bottom);
            m_regions[RightBottom] = QRect(width - m_right, height - m_bottom, m_right, m_bottom);
            m_regions[Bottom] = QRect(m_left, height - m_bottom, width - m_left - m_right, m_bottom);
            m_regions[LeftBottom] = QRect(0, height - m_bottom, m_left, m_bottom);
            m_regions[Left] = QRect(0, m_top, m_left, height - m_top - m_bottom);
            m_regions[LeftTop] = QRect(0, 0, m_left, m_top);
            m_regions[Inner] = QRect(m_left, m_top, width - m_left - m_right, height - m_top - m_bottom);
        }
    }
    
    TDragProxy::WidgetRegion TDragProxy::HitTest(const QPoint& pos)
    {
        for (int i = 0; i < 9; i++)
        {
            const QRect rect = m_regions[i];
            if (rect.contains(pos))
            {
                return TDragProxy::WidgetRegion(i);
            }
        }
        return Unknown;
    }
    
    void TDragProxy::SetDragEnable(bool bEnable)
    {
        m_bDragEnable = bEnable;
    }

    接口调用例子:

    setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint);
    setMinimumSize(MWS_MIN_WIDTH, MWS_MIN_HEIGHT);
    
    mpDragProxy = new TDragProxy(this);
    mpDragProxy->SetBorderWidth(MWS_BORD_WIDTH, MWS_BORD_WIDTH, MWS_BORD_WIDTH, MWS_BORD_WIDTH);
  • 相关阅读:
    数据结构——栈
    三种被击效果
    限制移动速度
    带冷却时间的按钮(二)
    带冷却时间的按钮(一)
    schedule和scheduleUpdate
    cocos2d-html5对话界面设计
    initWithSpriteFrameName和createWithSpriteFrameName
    sprite常用操作
    cc.RepeatForever和cc.Spawn冲突
  • 原文地址:https://www.cnblogs.com/sz-leez/p/5076341.html
Copyright © 2011-2022 走看看