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<QMouseEvent> 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章