头文件定义:
------------------------------------------------------------------
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);