使用setWindowFlags(Qt::FramelessWindowHint);设置后的窗体是不可以移动、拉伸的,所以为了让无边框窗体移动就需要自己重写一些事件实现。
效果如下
图1 拖拽窗体
(注:当窗体左上角、左边、上边拖拽时会有抖动,有些电脑却没有这种情况。。具体为啥我也不知道( ⊙o⊙?))
具体实现(九宫格法)
把一个窗体划分为9个部分如图
图2 九宫格
鼠标位于22区域代表移动,位于其他位置代表拖动
首先设置窗体属性
setWindowFlags(Qt::FramelessWindowHint); //无边框
//如果启用了鼠标跟踪,即使没有按下按钮,控件也会接收到鼠标移动事件。
setMouseTracking(true);
setMinimumSize(50,50);
- 实现鼠标进入相应的区域,鼠标的样式改变
鼠标样式有很多种类可以通过帮助文档的enum Qt::CursorShape枚举类型查看
主要使用的有
int row(QPointF pos); //计算九宫格行
int col(QPointF pos); //计算九宫格列
int moveArea(QPointF pos); //点击区域 相对于九宫格
void setMouseStyle(int moveArea);
前三个函数比较简单,这里给出源码
//其中m_nBorder是边界长度 也就是 九宫格中边缘的行和列宽度
int Widget::row(QPointF pos)
{
if(pos.y() < m_nBorder)
{
return 10;
}
else if(pos.y() > height() - m_nBorder)
{
return 30;
}
else
{
return 20;
}
}
int Widget::col(QPointF pos)
{
if(pos.x() < m_nBorder)
{
return 1;
}
else if(pos.x() > width() - m_nBorder)
{
return 3;
}
else
{
return 2;
}
}
int Widget::moveArea(QPointF pos)
{
return row(pos) + col(pos);
}
当鼠标MoveEvent事件触发时,设置鼠标样式,具体代码如下
void Widget::mouseMoveEvent(QMouseEvent *event)
{
setMouseStyle(moveArea(event->pos()));
}
void Widget::setMouseStyle(int moveArea)
{
switch (moveArea) {
case 11:
setCursor(Qt::SizeFDiagCursor);
break;
case 12:
setCursor(Qt::SizeVerCursor);
break;
case 13:
setCursor(Qt::SizeBDiagCursor);
break;
case 21:
setCursor(Qt::SizeHorCursor);
break;
case 22:
if(!m_bPress)
{
setCursor(Qt::OpenHandCursor);
}
break;
case 23:
setCursor(Qt::SizeHorCursor);
break;
case 31:
setCursor(Qt::SizeBDiagCursor);
break;
case 32:
setCursor(Qt::SizeVerCursor);
break;
case 33:
setCursor(Qt::SizeFDiagCursor);
break;
default:
setCursor(Qt::WaitCursor);
break;
}
}
通过以上设置即可实现鼠标进入窗体时,鼠标样式改变!
- 移动实现
移动实现的方法就是当前坐标和上一次坐标的差值作为窗体移动的变量
实现代码如下
//变量声明
bool m_bPress; //左鼠标点击实现移动
QPoint m_currentPos; //屏幕上点击的坐标点
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->buttons() == Qt::LeftButton)
{
m_bPress = true;
m_currentPos = event->globalPos();
}
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
if(m_bPress)
{
QPoint tempPos = event->globalPos() - m_currentPos;
move(pos() + tempPos);
m_currentPos = event->globalPos();
}
}
即可实现移动效果
图3 移动
- 最后实现拖拽效果
下面给出关键实现代码
QPoint tempPos = event->globalPos() - m_currentPos;
QRect rect=geometry(); //记录窗体当前位置
//鼠标左键处于拖拽拉伸区域
switch(m_flag) //m_flag为鼠标点击左键时 鼠标样式状态
{
case 11:
rect.setTopLeft(rect.topLeft()+tempPos); //左上角
break;
case 13:
rect.setTopRight(rect.topRight()+tempPos); //右上角
break;
case 31:
rect.setBottomLeft(rect.bottomLeft()+tempPos); //左下角
break;
case 33:
rect.setBottomRight(rect.bottomRight()+tempPos); //右下角
break;
case 12:
rect.setTop(rect.top()+tempPos.y()); //上
break;
case 21:
rect.setLeft(rect.left()+tempPos.x()); //左
break;
case 23:
rect.setRight(rect.right()+tempPos.x()); //右
break;
case 32:
rect.setBottom(rect.bottom()+tempPos.y()); //下
break;
default:
break;
}
this->setGeometry(rect);
}
通过以上步骤即可实现一个无边框的窗体移动、拖拽。