持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情
在QT中,我们设置值 Qt::FramelessWindowHint 之后,就把边框隐藏掉了,这个时候,对应的,鼠标也不能对齐调整大小和移动位置了。
我们在日常使用过程中,要是要自定义标题栏,又得去这样干,所以,我们需要重新让鼠标事件得到监听。
其实本质上来说,我们只需要让鼠标重新处理对应的事件,就可以达到我们的目的。
解决鼠标移动窗口
现在的需求是:
- 鼠标按下左键,光标变化
- 鼠标在按下左键时移动,重新设置窗口的起始坐标
- 鼠标松开左键,不再继续移动
在这里,需要重写三个虚函数 分别是:
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
重写函数的实现也比较简单,下列便是 (去掉了类名):
void mousePressEvent(QMouseEvent *event) {
if (event->button() == Qt::LeftButton)
{
is_drag = true; // 用于记录是否按下
drag = event->pos(); // 记录按下时的坐标
setCursor(Qt::SizeAllCursor); // 设置光标
}
}
void mouseReleaseEvent(QMouseEvent *event) {
if (event->button() == Qt::LeftButton)
{
is_drag = false;
setCursor(Qt::ArrowCursor); // 设置光标
}
}
void mouseMoveEvent(QMouseEvent *event) {
if (this->is_drag)
{
this->move(event->globalPos() - this->drag); // 移动窗口
}
}
解决调整大小问题
在看调整大小问题之前,你得先明白监听的原理
在QT中,鼠标移动事件默认不监听,除非等你开启 setMouseTracking(true);
每次移动监听事件都会交给 mouseMoveEvent来做,对应的,会有一个event事件,在其中,我们可以拿到其鼠标当前的坐标点。
现在将窗口划分为9个区域。
分别是:
enum state_region {
DEFAULT,
TOP, BOTTOM, LEFT, RIGHT,
LEFTTOP, LEFTBOTTOM,
RIGHTTOP, RIGHTBOTTOM
};
对应着这九个区域
现在,每次移动事件触发时,就会去刷新我们的状态,看它位于哪一个区域内
假设现在的边框为 5 的大小,来计算:
(计算机中的y轴是相反的)
计算出状态之后,然后去更新其鼠标光标之后,就可以调整移动了
设计调整大小有八种调整,其实是由四种调整组合而得到的
调整上方
调整上方是调整的整个矩形的高度,而上方的调整涉及到了矩形开始位置的 y轴的变化 所以,我们需要对新矩形的y轴进行调整
auto adjustTop = [&] {
if (bottomRight.y() - point.y() <= this->minimumHeight())
{
newRect.setY(topLeft.y());
}
else
{
newRect.setY(point.y());
}
};
调整左方
调整左方调整的是整个矩形的宽度,而左方调整涉及到了矩形左上角的变化,所以要更改 x轴的位置
auto adjustLeft = [&] {
if (bottomRight.x() - point.x() <= this->minimumWidth())
{
newRect.setLeft(topLeft.x());
}
else
{
newRect.setLeft(point.x());
};
};
调整下方
调整下方时,涉及到了高度的变化,可是并不涉及左上角变化,所以只用计算出新的高度即可
auto adjustBottom = [&] {
newRect.setHeight(point.y() - topLeft.y());
};
调整右方
调整左方时,不涉及左上角的变化,只用计算出新的宽度即可
auto adjustRight = [&] {
newRect.setWidth(point.x() - topLeft.x());
};
以上便是调整的大致逻辑
下面来看看代码(去掉了类名):
state_region refreshCursor(QPoint point)
{
auto x = rect().width();
auto y = rect().height();
auto dx = point.x();
auto dy = point.y();
if (dx <= PADDING) // 左
{
if (dy <= PADDING) // 上
{
return state_region::LEFTTOP;
}
else if(dy >= y - PADDING) // 下
{
return state_region::LEFTBOTTOM;
}
else // 中
{
return state_region::LEFT;
}
}
if (dx >= x - PADDING) // 右
{
if (dy <= PADDING) // 上
{
return state_region::RIGHTTOP;
}
else if(dy >= y - PADDING) // 下
{
return state_region::RIGHTBOTTOM;
}
else // 中
{
return state_region::RIGHT;
}
}
// 中
if (dy <= PADDING)
{
return state_region::TOP;
}
else if(dy >= y - PADDING)
{
return state_region::BOTTOM;
}
else
{
return state_region::DEFAULT;
}
}
void setRegionCursor()
{
switch (this->region_)
{
case state_region::TOP:
case state_region::BOTTOM:
setCursor(Qt::SizeVerCursor);
break;
case state_region::LEFT:
case state_region::RIGHT:
setCursor(Qt::SizeHorCursor);
break;
case state_region::LEFTBOTTOM:
case state_region::RIGHTTOP:
setCursor(Qt::SizeBDiagCursor);
break;
case state_region::LEFTTOP:
case state_region::RIGHTBOTTOM:
setCursor(Qt::SizeFDiagCursor);
break;
case state_region::DEFAULT:
if (!this->is_drag)
setCursor(Qt::ArrowCursor);
}
}
void mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
is_drag = true;
drag = event->pos(); // 记录相对位置
setCursor(Qt::SizeAllCursor);
is_region = (region_ != state_region::DEFAULT);
}
}
void mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
is_drag = false;
is_region = false;
setCursor(Qt::ArrowCursor);
}
}
QRect adjustRegion(QPoint point)
{
QRect rect = this->rect();
QPoint topLeft = mapToGlobal(rect.topLeft());
QPoint bottomRight = mapToGlobal(rect.bottomRight());
qInfo() << topLeft << "x" << bottomRight;
auto newRect = QRect(topLeft, bottomRight);
auto adjustLeft = [&] {
if (bottomRight.x() - point.x() <= this->minimumWidth())
{
newRect.setLeft(topLeft.x());
}
else
{
newRect.setLeft(point.x());
};
};
auto adjustTop = [&] {
if (bottomRight.y() - point.y() <= this->minimumHeight())
{
newRect.setY(topLeft.y());
}
else
{
newRect.setY(point.y());
}
};
auto adjustRight = [&] {
newRect.setWidth(point.x() - topLeft.x());
};
auto adjustBottom = [&] {
newRect.setHeight(point.y() - topLeft.y());
};
switch (this->region_)
{
case state_region::LEFT:
adjustLeft();
break;
case state_region::RIGHT:
adjustRight();
break;
case state_region::TOP:
adjustTop();
break;
case state_region::BOTTOM:
adjustBottom();
break;
case state_region::LEFTTOP:
adjustLeft();
adjustTop();
break;
case state_region::LEFTBOTTOM:
adjustLeft();
adjustBottom();
break;
case state_region::RIGHTTOP:
adjustRight();
adjustTop();
break;
case state_region::RIGHTBOTTOM:
adjustRight();
adjustBottom();
break;
default:
break;
}
return newRect;
}
void mouseMoveEvent(QMouseEvent *event)
{
region_ = refreshCursor(event->pos());
setRegionCursor();
if (this->is_drag)
{
if (region_ != state_region::DEFAULT)
{
this->setGeometry(adjustRegion(event->globalPos()));
}
else
{
if (!this->is_region)
this->move(event->globalPos() - this->drag);
}
}
}