Qt中的触屏事件

Qt中的触屏事件

1.启用触屏事件

当按下、松开或移动触摸设备(如触摸屏或触控板)上的一个或多个触摸点时,就会发生触摸事件。要接收触摸事件,部件必须设置 Qt::WA_AcceptTouchEvents 属性,图形项必须将 acceptTouchEvents 属性设置为 true。

使用基于 QAbstractScrollArea 的 widget 时,应在滚动区域的视口中启用 Qt::WA_AcceptTouchEvents 属性。

与 QMouseEvent 类似,Qt 会在 widget 首次按下时自动抓取每个触摸点,并且该 widget 将接收触摸点的所有更新,直到触摸点被释放。请注意,一个 widget 有可能接收多个触摸点的事件,而且多个 widget 可能同时接收触摸事件。

cpp 复制代码
在需要捕捉触屏的控件中增加
setAttribute(Qt::WA_AcceptTouchEvents);

如果是图形项
acceptTouchEvents(true);

2.事件处理

所有触摸事件都属于 QEvent::TouchBegin, QEvent::TouchUpdate, QEvent::TouchEnd 或 QEvent::TouchCancel 类型。为部件重新实现 QWidget::event() 或 QAbstractScrollArea::viewportEvent() 以及为图形视图中的项目重新实现 QGraphicsItem::sceneEvent() 以接收触摸事件。

与窗口部件不同,QWindow 可始终接收触摸事件,无需选择是否接收。在直接使用 QWindow 时,只需重新实现 QWindow::touchEvent()即可。

QEvent::TouchUpdate 和 QEvent::TouchEnd 事件会发送到接受 QEvent::TouchBegin 事件的部件或项目。如果 QEvent::TouchBegin 事件未被接受,也未被事件过滤器过滤,那么在下一次 QEvent::TouchBegin 之前,不会再发送触摸事件。

某些系统可能会发送 QEvent::TouchCancel 类型的事件。收到该事件后,应用程序将被要求忽略整个活动触摸序列。例如,在合成系统中,合成器可能会决定将某些手势视为全系统手势。每当做出这样的决定(手势被识别)时,客户端就会收到 QEvent::TouchCancel 事件的通知,从而可以相应地更新自己的状态。

cpp 复制代码
触屏事件类型:QEvent::TouchBegin, QEvent::TouchUpdate, QEvent::TouchEnd 或 QEvent::TouchCancel 类型。
要处理触屏事件,就要重写QWidget::event() 
如果要控件可以处理触屏事件,就要重写控件,然后重写控件中的QWidget::event() 函数。
如果是QAbstractScrollArea的滑块类型要重写QAbstractScrollArea::viewportEvent() 这个函数。
QWindow 可始终接收触摸事件,无需选择是否接收。在直接使用 QWindow 时,只需重新实现 QWindow::touchEvent()即可
cpp 复制代码
    virtual bool event(QEvent *e) override
    {
        switch (e->type())
        {
        case QEvent::TouchBegin:
            setTouchStyle();
            break;
        case QEvent::TouchUpdate:
            setHoverStyle();
            break;
        case QEvent::TouchEnd:
            setNormalStyle();
            break;
        default:
            break;
        }
        return QPushButton::event(e);
    }

touchPoints() 函数返回事件中包含的所有触摸点的列表。请注意,该列表可能是空的,例如在 QEvent::TouchCancel 事件中。可以使用 QTouchEvent::TouchPoint 类检索每个触摸点的信息。Qt::TouchPointState 枚举描述了触摸点可能具有的不同状态。

注意:touchPoints() 的列表永远不会是部分的: 触控事件将始终包含一个触控点,该触控点是针对发送事件的窗口或部件的每个现有物理触点。例如,假设所有触摸都针对同一个窗口或部件,那么条件为 touchPoints().count()==2 的事件保证意味着触摸触摸屏或触摸板的手指数正好是两个。

cpp 复制代码
说白了就是touchPoints()函数可以获取到触控点的信息。每个触控点的信息都不一样,有自己独立的信息。

3.事件传递和传播

默认情况下,QGuiApplication 会将 QTouchEvent 中的第一个触摸点转换为 QMouseEvent。这使得在通常不处理 QTouchEvent 的现有部件上启用触摸事件成为可能。有关这样做时需要特别考虑的信息,请参阅下文。

QEvent::TouchBegin 是发送给 widget 的第一个触摸事件。QEvent::TouchBegin 事件包含一个特殊的接受标志,表示接收者是否需要该事件。默认情况下,事件被接受。如果您的 widget 未处理触摸事件,则应调用 ignore()。QEvent::TouchBegin 事件会沿着父窗口部件链向上传播,直到某个窗口部件使用 accept() 接受了该事件,或者某个事件过滤器消耗了该事件。对于 QGraphicsItems,QEvent::TouchBegin 事件会传播到鼠标下的项目(类似于 QGraphicsItems 的鼠标事件传播)。

4.触摸点分组

如上所述,多个部件有可能同时接收 QTouchEvents。但是,Qt 确保不会向同一个窗口部件发送重复的 QEvent::TouchBegin 事件,例如,如果用户触摸了 QGroupBox 中的两个不同窗口部件,而这两个窗口部件都忽略了 QEvent::TouchBegin 事件,那么在传播过程中理论上就会发生这种情况。

为了避免这种情况,Qt 将使用以下规则把新的触摸点分组:

当检测到第一个触摸点时,目的地部件首先由屏幕上的位置决定,其次由传播规则决定。

当检测到其他触摸点时,Qt 会首先查看新触摸点下的 widget 的任何祖先或后代是否有活动触摸点。如果有,新的触摸点将与第一个触摸点分组,新的触摸点将以单个 QTouchEvent 发送给处理第一个触摸点的 widget。(新触摸点下的部件不会收到事件)。

这样,同级部件就可以独立处理触摸事件,同时确保 QTouchEvents 的顺序始终正确。

5.鼠标事件和触摸事件合成

QTouchEvent 的传递独立于 QMouseEvent。应用程序标志 Qt::AA_SynthesizeTouchForUnhandledMouseEvents 和 Qt::AA_SynthesizeMouseForUnhandledTouchEvents 可用来启用或禁用触摸事件到鼠标事件和鼠标事件到触摸事件的自动合成。

6.注意事项

如上所述,启用触摸事件意味着多个部件可以同时接收触摸事件。结合默认的 QWidget::event() QTouchEvents 处理功能,这将为您设计触摸用户界面提供极大的灵活性。请注意其中的影响。例如,用户有可能用一只手指移动 QSlider,另一只手指按下 QPushButton。这些部件发出的信号将交错出现。

不支持使用 QTouchEvent 事件处理程序中的 exec() 方法(如 QDialog::exec() 或 QMenu::exec())递归到事件循环。由于存在多个事件接收者,递归可能会导致问题,包括但不限于事件丢失和意外的无限递归。

QTouchEvents 不受鼠标抓取或活动弹出窗口部件的影响。当打开弹出窗口或抓取鼠标时有多个活动触摸点,QTouchEvents 的行为是未定义的。

另请参阅 QTouchEvent::TouchPoint、Qt::TouchPointState、Qt::WA_AcceptTouchEvents 和 QGraphicsItem::acceptTouchEvents()。

相关推荐
禁默几秒前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Code哈哈笑9 分钟前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
程序猿进阶13 分钟前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
qq_4336184415 分钟前
shell 编程(二)
开发语言·bash·shell
charlie11451419130 分钟前
C++ STL CookBook
开发语言·c++·stl·c++20
袁袁袁袁满30 分钟前
100天精通Python(爬虫篇)——第113天:‌爬虫基础模块之urllib详细教程大全
开发语言·爬虫·python·网络爬虫·爬虫实战·urllib·urllib模块教程
ELI_He99936 分钟前
PHP中替换某个包或某个类
开发语言·php
m0_7482361144 分钟前
Calcite Web 项目常见问题解决方案
开发语言·前端·rust
倔强的石头1061 小时前
【C++指南】类和对象(九):内部类
开发语言·c++
Watermelo6171 小时前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript