QWheelEvent 使用分析一例

本文探讨了在Qt环境下,当鼠标在Spinbox内时滚轮事件有效,移出Spinbox后无效的问题,并详细解释了事件转发与接受的概念。通过代码示例,演示了解决方案:在自定义的wheelEvent中调用event的ignore方法来控制事件的转发,而不是直接忽略事件。最终提供了完整示例代码,帮助开发者理解和解决类似问题。

缘起

一网友问:

在VS里用Qt新建一个含mainwindow的项目,然后里面添加一个spinbox。除此之外啥都不做。
运行后,鼠标在spinbox内的时候,滚轮有效,移到spinbox外,无效。
在这种情况下,如何使滚轮在spinbox外对其有效?

答案其实很简单,QWheelEvent 的 Manual中如此描述(可是,你真的理解这句话了么?):

Wheel events are sent to the widget under the mouse cursor, but if that widget does not handle the event they are sent to the focus widget. 

一点弯路

说实话,这句话一开始我没有理解。相信大家也是一样,特别是,和它紧挨着还有这样一句话:

A wheel event contains a special accept flag that indicates whether the receiver wants the event. You should call ignore() if you do not handle the wheel event; this ensures that it will be sent to the parent widget.

看起来答案应该很明确,对吧?我们在派生类中override基类的wheelEvent(),然后对事件调用ignore()不就行了??

答案是:不行!!

事件转发?

我们在  Qt事件系统   一文中提到了事件转发,它描述的是这样一种情况:

+------------+
|     C      |
| +-------+  |
| |   B   |  |
| | +--+  |  |
| | |  |  |  |
| | | A|  |  |
| | +--+  |  |
| +-------+  |
+------------+

假定有父子关系的3个Widget:A、B、C(C是顶级窗口)。我们现在在 A 上点击鼠标:

  • 如果A没有接受该事件(ignore),那么事件将转发到B
  • 如果B依然没有接受,将转发到C
  • 即使C不接受,但由于已经是顶级窗口,事件也将停止传递。

所以,我们应该看清楚了:Manual中这个句子描述的是事件转发时的处理。

但前一节的那个句子不是事件转发。二者没有联系!!

WheelEvent

  Qt源码学习(从Win32到Qt)   一文中,我们举得就是Wheel Event的例子。它不属于我们前面提到的事件转发行为。

我们重新看看这段代码(它在窗口的回调函数中被调用,将系统的Wheel事件转换成Qt的Wheel事件,而后派发):

  • 首先是定位光标下的widget,将事件发送到该widget中(注意popup widget的处理)
  • 如果该widget不接受(sendSpontaneousEvent返回false)
    • 则查找当前拥有焦点的widget,让事件发送到该焦点widget

看到差别了吧:

 

要求

事件转发

返回true,但event被ignore

此处

返回false

注意:QWidget::event()的Manual中有些关于事件转发的介绍,请注意查看(此处略)。

如何解决?

答案至此已经很明确了:

  • 在wheelEvent()中,我们只能调用event的accept或ignore,这个只会影响到事件转发
  • 要影响返回值,我们必须override基类的 event() 函数让其返回false才行

一个完整的例子如下:

<think>好的,用户想了解QtQWheelEvent的用法和示例。首先,我需要回忆一下QWheelEvent的基本知识。QWheelEvent用于处理鼠标滚轮事件,包括滚轮的方向、角度增量和像素增量等。用户可能需要知道如何在Qt应用程序中捕获和处理这些事件,比如缩放视图或者滚动内容。 接下来,我应该考虑如何在Qt部件中安装事件过滤器或者重写事件处理函数。通常的做法是子类化一个QWidget或其派生类,比如QGraphicsView或QOpenGLWidget,然后重写wheelEvent方法。这里需要提到eventFilter的使用,特别是如果用户想要在自定义控件中处理滚轮事件的话。 然后,我需要查找相关的示例代码。比如,在之前的引用中,用户提到了QOpenGLWidget的使用,可能涉及到paintGL和initializeGL。不过对于QWheelEvent,重点是wheelEvent的重写。记得要提到如何获取滚轮的delta值,以及处理像素和角度增量。 另外,需要注意Qt的不同版本之间可能有差异,比如Qt5和Qt6中QWheelEvent的变化。比如,Qt6使用position()代替了pos(),angleDelta()返回的是QPoint,而像素增量则是pixelDelta()。这些差异可能会导致用户的代码需要调整,特别是如果他们正在迁移项目的话。 还需要考虑用户可能的实际应用场景,比如在图形视图中实现缩放功能,或者在地图应用中滚动。这时候,示例代码应该展示如何根据滚轮事件调整视图的缩放因子,并调用update来重绘界面。 另外,用户可能需要知道如何处理平滑滚动事件,比如触控板的滚动手势,这时候pixelDelta()的值会更精确,而传统的angleDelta()可能更适合普通的鼠标滚轮。因此,在代码示例中最好同时处理这两种情况,确保兼容性。 还要注意引用之前提供的站内引用,比如引用[1]中的eventFilter示例,引用[2]中的QOpenGLWidget相关功能,但主要关注点是在QWheelEvent使用上。可能需要提到如何在QOpenGLWidget的子类中处理滚轮事件,结合update()函数来触发重绘。 最后,生成的相关问题需要围绕用户可能进一步想了解的内容,比如不同Qt版本的差异、如何实现视图缩放、以及如何优化事件处理性能等。确保问题能够引导用户深入学习和解决问题。</think>### QtQWheelEvent的用法与示例 在Qt中,`QWheelEvent`用于处理鼠标滚轮事件,常用于实现视图缩放、滚动条控制等功能。以下是具体用法和示例: --- #### 1. **基础用法** 通过重写`wheelEvent(QWheelEvent *event)`方法处理滚轮事件: ```cpp #include <QWidget> #include <QWheelEvent> class CustomWidget : public QWidget { protected: void wheelEvent(QWheelEvent *event) override { // 获取滚轮滚动方向和增量 QPoint angleDelta = event->angleDelta(); // 角度增量(传统鼠标滚轮) QPoint pixelDelta = event->pixelDelta(); // 像素增量(高精度设备,如触控板) // 判断垂直滚动 if (!angleDelta.isNull()) { if (angleDelta.y() > 0) { // 向上滚动,放大视图 zoomIn(); } else { // 向下滚动,缩小视图 zoomOut(); } } event->accept(); // 标记事件已处理 } private: void zoomIn() { /* 实现放大逻辑 */ } void zoomOut() { /* 实现缩小逻辑 */ } }; ``` --- #### 2. **在QGraphicsView中实现缩放** 结合`QGraphicsView`进行视图缩放时,需注意坐标系转换: ```cpp class CustomGraphicsView : public QGraphicsView { protected: void wheelEvent(QWheelEvent *event) override { if (event->modifiers() & Qt::ControlModifier) { // 按住Ctrl时缩放 qreal factor = (event->angleDelta().y() > 0) ? 1.1 : 0.9; scale(factor, factor); event->accept(); } else { QGraphicsView::wheelEvent(event); // 默认滚动行为 } } }; ``` --- #### 3. **Qt5与Qt6的差异** - **Qt5**:使用`delta()`获取滚动量,`orientation()`判断方向(已过时)。 - **Qt6**:改用`angleDelta()`和`pixelDelta()`,且坐标通过`position()`获取[^1][^3]。 --- #### 4. **在QOpenGLWidget中应用** 结合引用[2]提到的`QOpenGLWidget`,可在3D渲染中控制视角: ```cpp class GLWidget : public QOpenGLWidget { protected: void wheelEvent(QWheelEvent *event) override { // 根据滚轮调整相机距离 camera_distance -= event->angleDelta().y() * 0.1; update(); // 触发重绘 } void paintGL() override { // 根据camera_distance更新投影矩阵 } }; ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值