QT_QMainWindow实现鼠标移动监测事件

[背景]

如果不要QMainWindow自带的标题栏和状态栏,需要自定义的无边框状态时,我们在移除QMainWindow自带的标题栏和状态栏后,窗体就不能移动和拉伸缩放了。需要代码实现窗体无边框状态的移动和拉伸缩放功能。

w.setWindowFlags(Qt::FramelessWindowHint);//移除标题栏

w.setMouseTracking(true);//此属性保存是否为小部件启用鼠标跟踪,如果禁用了鼠标跟踪(默认值),则当移动鼠标时至少按下一个鼠标按钮时,小部件仅接收鼠标移动事件。如果启用了鼠标跟踪,即使没有按下按钮,小部件也会接收鼠标移动事件。

然后重写三个事件

void mousePressEvent(QMouseEvent *event) override;//获取鼠标的移动

void mouseMoveEvent(QMouseEvent *event) override;//获取鼠标的点击

void mouseReleaseEvent(QMouseEvent *event) override;//获取鼠标的释放

[问题]

以上设置在Qwidgets中完全ok,但如果是QMainWindow,mouseMoveEvent只能在鼠标按下时才反应。

[原因]

使用UI(QT设计师)添加控件,那么在QMainWindow窗体上会自动添加一个centralWidget层,而我们使用的是QMAinWindow的鼠标移动监测事件,

centralWidget将QMainWindow遮挡住了,所以鼠标移动也无法进入mouseMoveEvent。

[方法1:同步设置相关联的部件setMouseTracking(true)]

●原理:CentrolWidget 是 QMainWindow 的子类,你如果在子类上响应鼠标事件,只会触发子类的 mouseMoveEvent,根据C++继承和重载的原理,所以子类也要 setMouseTracking(true);所以如果你想响应鼠标事件的控件被某个父控件包含,则该控件及其父控件或容器也需要 setMouseTracking(true);

●例子:

w.setWindowFlags(Qt::FramelessWindowHint);//移除标题栏

ui->centralwidget->setMouseTracking(true);//首先设置centralwidget,注意和QWidgets(QWidgets是直接setMouseTracking(true)就行)的区别。

    setMouseTracking(true);//下面就是从父级开始向下相关联的部件都得设置。

    ui->widget->setMouseTracking(true);

    ui->widget_2->setMouseTracking(true);

    ui->widget_3->setMouseTracking(true);

ui->widget_4->setMouseTracking(true);

●评价:最有效的办法,因为效果很好、难点在于要找出所有相关的控件进行设置,要排查梳理所有控件之间的父子级关系等,如果控件很多,这样做操作有点麻烦。

 [方法2:grabMouse()和releaseMouse()组合使用]

●原理:

在鼠标移动时捕获鼠标事件,然后在鼠标离开窗口时结束捕获鼠标事件,可以在mouseMoveEvent()函数中调用grabMouse()函数,然后在leaveEvent()函数中调用releaseMouse()函数。这样做可以实现一些跟随鼠标的效果。

如果想要在其他情况下捕获或释放鼠标事件,可以根据自己的需求选择合适的时机和方式。但是注意,不要忘记释放鼠标,否则会影响其他控件的正常使用。

●例子:

     2.1 main中设置w.setWindowFlags(Qt::FramelessWindowHint);

     w.setMouseTracking(true);

2.2 Maindown的构造函数中设置ui->centralwidget->setMouseTracking(true);

2.3 重写void MainWindow::enterEvent(QEvent *event)函数,即.h中加

protected:

void mousePressEvent(QMouseEvent *event) override;

.cpp中加

void MainWindow::enterEvent(QEvent *event)//进入窗体的事件

{

grabMouse();

}

2.4 记住mouseReleaseEvent函数中要加releaseMouse();

void MainWindow::mouseReleaseEvent(QMouseEvent *event)

{

releaseMouse();

//m_bLeftPress = false;

//QApplication::restoreOverrideCursor();

}

●评价:

使用grabMouse()函数有一些缺点,例如导致窗体其它控件不能点击。这是因为当一个widget调用grabMouse()函数时,其他widget将无法接收到鼠标事件,导致程序异常或无法响应鼠标事件。因此,如果使用grabMouse()函数捕获了鼠标事件,需确保在适当的时候释放鼠标,以允许其他widget接收到鼠标事件。可以使用releaseMouse()函数来释放鼠标捕获。这种方式实际运用不容易掌控,尤其是控件能否点击和鼠标捕捉释放之间的平衡。

[相关小菜]

●QCursor::pos()和event->globalPos()的区别:

QCursor::pos()返回的是鼠标指针在屏幕坐标系中的当前位置,而event->globalPos()返回的是鼠标指针在屏幕坐标系中的事件发生时的位置。1

QCursor::pos()是直接访问鼠标指针的位置,而event->globalPos()是通过事件系统传递的位置。1

QCursor::pos()和event->globalPos()在正常情况下应该是相同或接近的,但如果鼠标移动太快或事件处理延迟,可能会有一些差异。

QCursor::pos()和event->globalPos()都是全局坐标,如果要转换为窗口或控件的相对坐标,需要使用mapFromGlobal()函数。

●event->pos().x()和event->globalPos()的区别:

前者是事件(event)的位置(pos())的横坐标(x()),表示事件发生时鼠标相对于窗口(window)的左上角(0,0)的水平距离;后者是事件(event)的全局位置(globalPos()),表示事件发生时鼠标相对于桌面(desktop)的左上角(0,0)的水平和垂直距离。这两者的值可能不同,因为窗口和桌面的左上角可能不重合,而且鼠标的位置可能在事件发生后发生变化。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值