QMainwindow的鼠标跟踪事件不触发问题
一、无边框窗口实现代码
1.1 头文件
class EtcTestTool : public QMainWindow
{
Q_OBJECT
public:
EtcTestTool(QWidget *parent = Q_NULLPTR);
private:
void InitialUi();
//...
protected:
void mousePressEvent(QMouseEvent*event)override;
void mouseReleaseEvent(QMouseEvent*event)override;
void mouseMoveEvent(QMouseEvent*event)override;
private:
// 鼠标的 活动范围的枚举
enum MousePosition
{ /* 这里我们将一个窗口划分为9个区域,分别为
左上角(1, 1)、中上(2,1)、右上角(3, 1)
左中 (1, 2)、 中间(2, 2)、右中 (3, 2)
左下角(1, 3)、中下(2,3)、 右下角(3, 3)
10*x+y区分各个区域
*/
LeftTop = 11,
Top = 21,
RightTop = 31,
Left = 12,
Mid = 22,
Right = 32,
LeftBottom = 13,
Bottom = 23,
RightBottom = 33
};
//根据鼠标的设置鼠标样式,用于拉伸
void SetMouseCursor(int x, int y);
//判断鼠标的区域,用于拉伸
int GetMouseRegion(int x, int y);
private:
QPoint m_windowsLastPs;
QPoint m_mouseLastPs;
int m_mouse_press_region = MousePosition::Mid;
QPoint m_dragStartPos;
bool m_bPressing = false;
private:
Ui::EtcTestToolClass ui;
};
1.2 实现文件
EtcTestTool::EtcTestTool(QWidget *parent)
: QMainWindow(parent)
{
setWindowFlags(Qt::FramelessWindowHint);
ui.setupUi(this);
InitialUi();
//...
}
void EtcTestTool::InitialUi()
{
//mainwindow的鼠标跟踪事件被子控件遮挡拦截
this->setMouseTracking(true);
ui.centralWidget->setMouseTracking(true);
ui.frame->setMouseTracking(true);
ui.frmTitle->setMouseTracking(true);
ui.groupBox->setMouseTracking(true);
//...
}
void EtcTestTool::on_btnMin_clicked()
{
showMinimized();
}
void EtcTestTool::on_btnMax_clicked()
{
if (isMaximized())
{
showNormal();
ui.btnMax->setProperty("Max", false);
}
else
{
showMaximized();
ui.btnMax->setProperty("Max", true);
}
ui.btnMax->style()->polish(ui.btnMax);
}
void EtcTestTool::on_btnClose_clicked()
{
close();
}
void EtcTestTool::mousePressEvent(QMouseEvent*event)
{
if (event->button() == Qt::LeftButton)
{
// 如果是鼠标左键
// 获取当前窗口位置,以窗口左上角为标定
m_windowsLastPs = pos();
// 获取鼠标在屏幕的位置 就是全局的坐标 以屏幕左上角为坐标系
m_mouseLastPs = event->globalPos();
m_bPressing = true;
m_mouse_press_region = GetMouseRegion(event->pos().x(), event->pos().y());
}
QWidget::mousePressEvent(event);
}
void EtcTestTool::mouseReleaseEvent(QMouseEvent*event)
{
if (event->button() == Qt::LeftButton)
{
m_bPressing = false;
}
setCursor(QCursor{});
QWidget::mousePressEvent(event);
}
void EtcTestTool::mouseMoveEvent(QMouseEvent*event)
{
// 设置鼠标的形状
SetMouseCursor(event->pos().x(), event->pos().y());
// 计算的鼠标移动偏移量, 就是鼠标全局坐标 - 减去点击时鼠标坐标
QPoint point_offset = event->globalPos() - m_mouseLastPs;
if ((event->buttons() == Qt::LeftButton) && m_bPressing)
{
if (m_mouse_press_region == Mid)
{
// 如果鼠标是在窗口的中间位置,就是移动窗口
move(m_windowsLastPs + point_offset);
}
else {
// 其他部分 是拉伸窗口
// 获取客户区
QRect rect = geometry();
switch (m_mouse_press_region)
{
// 左上角
case LeftTop:
rect.setTopLeft(rect.topLeft() + point_offset);
break;
case Top:
rect.setTop(rect.top() + point_offset.y());
break;
case RightTop:
rect.setTopRight(rect.topRight() + point_offset);
break;
case Right:
rect.setRight(rect.right() + point_offset.x());
break;
case RightBottom:
rect.setBottomRight(rect.bottomRight() + point_offset);
break;
case Bottom:
rect.setBottom(rect.bottom() + point_offset.y());
break;
case LeftBottom:
rect.setBottomLeft(rect.bottomLeft() + point_offset);
break;
case Left:
rect.setLeft(rect.left() + point_offset.x());
break;
default:
break;
}
setGeometry(rect);
m_mouseLastPs = event->globalPos();
}
}
QWidget::mousePressEvent(event);
}
void EtcTestTool::SetMouseCursor(int x, int y)
{
// 鼠标形状对象
Qt::CursorShape cursor{};
int region = GetMouseRegion(x, y);
switch (region)
{
case LeftTop:
case RightBottom:
cursor = Qt::SizeFDiagCursor; break;
case RightTop:
case LeftBottom:
cursor = Qt::SizeBDiagCursor; break;
case Left:
case Right:
cursor = Qt::SizeHorCursor; break;
case Top:
case Bottom:
cursor = Qt::SizeVerCursor; break;
caseMid:
cursor = Qt::ArrowCursor; break;
default:
break;
}
setCursor(cursor);
}
int EtcTestTool::GetMouseRegion(int x, int y)
{
int region_x = 0, region_y = 0;
// 鼠标的X坐标小于 边界 说明他在最上层区域 第一区域
if (x < kMouseBorderSize)
{
region_x = 1;
}
else if (x > (this->width() - kMouseBorderSize)) {
region_x = 3;
}
else {
region_x = 2;
}
if (y < kMouseBorderSize)
{
region_y = 1;
}
else if (y > (this->height() - kMouseBorderSize)) {
region_y = 3;
}
else {
region_y = 2;
}
return region_x * 10 + region_y;
}
二、鼠标移动事件无法触发
2.1 现象和原因
Qt默认鼠标跟踪事件是关闭的,只有按下鼠标左键移动时才会触发;所以需要setMouseTracking(true)开启鼠标追踪事件。但是开启后仍然无法在不按左键情况下触发鼠标移动事件,后发现软件复写的QMainWindow的mouseMoveEvent函数,但是QMainWindow界面被centralWidget和布局的各种widget遮挡导致鼠标移动事件无法触发。
2.2 解决方案
解决方案:将QMainWindow的子控件centralWidget等同样开启鼠标跟踪事件setMouseTracking(true),则子控件的鼠标移动事件会通过事件循环传递到父类的QMainWindow中,最终触发QMainWindow的mouseMoveEvent函数。
void EtcTestTool::InitialUi()
{
//mainwindow的鼠标跟踪事件被子控件遮挡拦截,
this->setMouseTracking(true);
ui.centralWidget->setMouseTracking(true);
ui.frame->setMouseTracking(true);
ui.frmTitle->setMouseTracking(true);
ui.groupBox->setMouseTracking(true);
//...
}