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);
ps:本博文只用于日常备注及学习交流,请勿用于任何商业用途,涉及网摘等资料如有侵犯原作者权利,请联系确保及时更正!