【问题标题】:Object to process touch event but also let it through处理触摸事件但也让它通过的对象
【发布时间】:2016-05-20 15:08:28
【问题描述】:

我想创建一个像MultiPointTouchArea 一样工作的对象(因此它会有 touchUpdated 信号)但它不会窃取触摸,因此放置在它下面的对象也将接收触摸事件。

解决方案可能需要创建 C++ 对象。

有没有一种简单的方法来创建这样的对象?是否可以在不“窃取”事件的情况下处理(触摸)事件?任何提示将不胜感激。


这是我正在尝试做的一个例子。我想触顶Rectangle,但同时我想要MultiPointTouchAreas 进程触动:

import QtQuick 2.3
import QtQuick.Window 2.2

Window {
    visible: true
    width: 300
    height: 300

    Rectangle {
        id: rectangle1
        anchors.centerIn: parent
        width: 150
        height: width
        color: "red"
        MultiPointTouchArea {
            anchors.fill: parent
            mouseEnabled: false
            onTouchUpdated: {
                console.log("Bottom touch area contains:",
                            touchPoints.length,
                            "touches.")
            }
        }
    }
    Rectangle {
        id: rectangle2
        anchors.centerIn: parent
        width: 100
        height: width
        color: "blue"
        MultiPointTouchArea {
            anchors.fill: parent
            mouseEnabled: false
            onTouchUpdated: {
                console.log("Top touch area contains:",
                            touchPoints.length,
                            "touches.")
            }
        }
    }
}

如果我能找到可行的解决方案,我会在此处发布。我现在将尝试实现Mitchsolution

【问题讨论】:

  • 您是否尝试过将MultiPointTouchArea.mouseEnabled 设置为false?
  • @mkrus 我试过了。它不工作。

标签: event-handling qml qt5 touch-event


【解决方案1】:

您可以继承QQuickItem 并覆盖touchEvent() 函数:

此事件处理程序可以在子类中重新实现,以接收项目的触摸事件。事件信息由event参数提供。

您可能需要将 accepted 显式设置为 false 以确保该项目不会窃取事件:

设置accept参数表示事件接收者想要该事件。不需要的事件可能会传播到父小部件。默认情况下,isAccepted() 设置为 true,但不要依赖它,因为子类可能会选择在其构造函数中清除它。


我可以验证,上述操作会导致下触摸区域在按下后处理所有事件(在 Android 手机上测试)。在这种情况下,您需要以某种方式过滤事件。一种方法是,在您的 QQuickItem 子类中,声明一个将用于指向下部触摸区域的属性。当该属性发生变化时,在触摸区域安装一个事件过滤器:

ma​​in.cpp:

#include <QGuiApplication>
#include <QtQuick>

class CustomTouchArea : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(QQuickItem *targetTouchArea READ targetTouchArea WRITE setTargetTouchArea NOTIFY targetTouchAreaChanged)

public:
    CustomTouchArea() :
        mTargetTouchArea(0) {
    }

    bool eventFilter(QObject *, QEvent *event) {
        if (event->type() == QEvent::TouchUpdate) {
            qDebug() << "processing TouchUpdate...";
        }
        // other Touch events here...

        return false;
    }

    QQuickItem *targetTouchArea() const {
        return mTargetTouchArea;
    }

    void setTargetTouchArea(QQuickItem *targetTouchArea) {
        if (targetTouchArea == mTargetTouchArea)
            return;

        if (mTargetTouchArea)
            mTargetTouchArea->removeEventFilter(this);

        mTargetTouchArea = targetTouchArea;

        if (mTargetTouchArea)
            mTargetTouchArea->installEventFilter(this);

        emit targetTouchAreaChanged();
    }

signals:
    void targetTouchAreaChanged();

private:
    QQuickItem *mTargetTouchArea;
};

int main(int argc, char *argv[])
{
    QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    qmlRegisterType<CustomTouchArea>("App", 1, 0, "CustomTouchArea");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

#include "main.moc"

ma​​in.qml:

import QtQuick 2.3
import QtQuick.Window 2.2

import App 1.0

Window {
    visible: true
    width: 300
    height: 300

    Rectangle {
        id: rectangle1
        anchors.centerIn: parent
        width: 150
        height: width
        color: "red"
        MultiPointTouchArea {
            id: touchArea
            anchors.fill: parent
            mouseEnabled: false
            onTouchUpdated: {
                console.log("Bottom touch area contains:",
                            touchPoints.length,
                            "touches.")
            }
        }
    }
    Rectangle {
        id: rectangle2
        anchors.centerIn: parent
        width: 100
        height: width
        color: "blue"
        CustomTouchArea {
            targetTouchArea: touchArea
            anchors.fill: parent
        }
    }
}

您可以阅读有关事件过滤器的更多信息here

【讨论】:

  • 我对此有疑问。我可以覆盖touchEvent() 函数,但如果我调用setAccepted(false),我将停止接收事件,然后它们将被发送到下面的对象。看来同一个QEvent一次只能被一个对象使用。
  • 没错,我没有测试过。答案已更新。
猜你喜欢
  • 2015-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-09
  • 2012-10-26
  • 2010-12-02
相关资源
最近更新 更多