QML防止鼠标事件被过滤(窃取)

如果将 MouseArea 放置在筛选 child 鼠标事件的 Item(例如 Flickable、SwipeView )中,则当父 Item 识别出手势(例如滑动)时,鼠标事件可能会从 MouseArea 中被过滤。如果将 preventStealing 属性设置为 true,则任何 Item 都不会窃取该 MouseArea 的鼠标事件。(注意,一旦某 Item 开始窃取事件,将 preventStealing 设置为 true 后,直到下一次相关事件才生效)

这个属性是 MouseArea 的,那么对于我们自定义的 C++ QQuickItem 该如何处理呢?通过 Qt 源码,可以看到是调用 QQuickItem 的 setKeepMouseGrab 函数进行设置(配合 setAcceptedMouseButtons(Qt::LeftButton) 启用了鼠标事件才有效)。

相关 Qt 源码:

//MouseArea

bool QQuickMouseArea::preventStealing() const
{
    Q_D(const QQuickMouseArea);
    return d->preventStealing;
}

void QQuickMouseArea::setPreventStealing(bool prevent)
{
    Q_D(QQuickMouseArea);
    if (prevent != d->preventStealing) {
        d->preventStealing = prevent;
        setKeepMouseGrab(d->preventStealing && d->enabled);
        emit preventStealingChanged();
    }
}

//Flickable

bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event)
{
    Q_D(QQuickFlickable);
    QPointF localPos = mapFromScene(event->windowPos());

    Q_ASSERT_X(receiver != this, "", "Flickable received a filter event for itself");
    if (receiver == this && d->stealMouse) {
        // we are already the grabber and we do want the mouse event to ourselves.
        return true;
    }

    bool receiverDisabled = receiver && !receiver->isEnabled();
    bool stealThisEvent = d->stealMouse;
    bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab());
    if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) {
        QScopedPointer mouseEvent(QQuickWindowPrivate::cloneMouseEvent(event, &localPos));
        mouseEvent->setAccepted(false);

        switch (mouseEvent->type()) {
        case QEvent::MouseMove:
            d->handleMouseMoveEvent(mouseEvent.data());
            break;
        case QEvent::MouseButtonPress:
            d->handleMousePressEvent(mouseEvent.data());
            d->captureDelayedPress(receiver, event);
            stealThisEvent = d->stealMouse;   // Update stealThisEvent in case changed by function call above
            break;
        case QEvent::MouseButtonRelease:
            d->handleMouseReleaseEvent(mouseEvent.data());
            stealThisEvent = d->stealMouse;
            break;
        default:
            break;
        }
        if ((receiver && stealThisEvent && !receiverKeepsGrab && receiver != this) || receiverDisabled) {
            d->clearDelayedPress();
            grabMouse();
        } else if (d->delayedPressEvent) {
            grabMouse();
        }

        const bool filtered = stealThisEvent || d->delayedPressEvent || receiverDisabled;
        if (filtered) {
            event->setAccepted(true);
        }
        return filtered;
    } else if (d->lastPosTime != -1) {
        d->lastPosTime = -1;
        returnToBounds();
    }
    if (event->type() == QEvent::MouseButtonRelease || (receiverKeepsGrab && !receiverDisabled)) {
        // mouse released, or another item has claimed the grab
        d->lastPosTime = -1;
        d->clearDelayedPress();
        d->stealMouse = false;
        d->pressed = false;
    }
    return false;
}

 参考 Qt 文档:https://doc.qt.io/qt-5/qml-qtquick-mousearea.html

参考 Qt 源码:E:\Qt\qt-everywhere-src-5.15.0\qtdeclarative\src\quick\items\qquickmousearea_p.h

你可能感兴趣的:(QML,三言两语)