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()。

相关推荐
用户805533698031 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner1 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz6 天前
QML Hello World 入门示例
qt
xcyxiner9 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner10 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner10 天前
DicomViewer (添加模型类)3
qt
xcyxiner11 天前
DicomViewer (目录调整) 2
qt
xcyxiner11 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00613 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术13 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript