首页 文章

将模拟MouseEvents(拖动目的)传播给父项

提问于
浏览
0

我正在研究Qt / Qml应用程序 .

我正在尝试通过Qt模拟拖动QML元素(Listview,Flickable ......)的拖动行为以进行测试 .

我有一个特定的问题,我想用最通用的解决方案来解决,我的组件是一个非交互式ListView,由交互式ListView嵌套,嵌套自己的MouseArea:

ListView {
    anchors.fill: parent
    interactive: false
    ListView {
        anchors.fill: parent
        MouseArea {
             ...
        }
    }
}

所以 . 我的想法是:获取一个QML对象,移动开始的局部坐标(x,y),找到它在位置上最嵌套的子项并将运动(dx,dy)应用于该子项 . 如果我正确理解QT / QML是如何工作的,如果孩子没有使用它,它应该将事件发送给父,并且Flickable组件应该能够检测拖动并捕获它们 .

void xx::touchAndDrag(QObject *object, const int x, const int y, const int dx, const int dy)
{

    timer = new QTimer(this);
    timerIteration = 0;
    deltaPoint = new QPointF(dx, dy);
    parentItem = qobject_cast<QQuickItem *>(object);
    item = parentItem;
    startPoint = QPointF(x, y);
    QPointF tempPoint = startPoint;

    for( ;; ) {
        //Find the most nested child at coordinate
        QQuickItem* child = item->childAt(tempPoint.x(), tempPoint.y());
        if(child) {
            item = child;
            tempPoint = child->mapFromItem(parentItem, tempPoint);
            qDebug() << "child found " << item;
        } else {
            break;
        }
    }

    timer->setInterval(movementDuration / nbIteration);
    qDebug() << "interval " << timer->interval();
    timer->setSingleShot(false);
    connect(timer, SIGNAL(timeout()), this, SLOT(mouseMove()));

    // Send press event at starting point
    QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress, item->mapFromItem(parentItem, startPoint), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier );
    qDebug() << "press " << e;
    qApp->postEvent(item, e);

    timer->start();
}

void xx::mouseMove()
{
    timerIteration++;
    QMouseEvent *e;
    if(timerIteration < nbIteration) {
        int x = startPoint.x() + deltaPoint->x() * timerIteration / nbIteration;
        int y = startPoint.y() + deltaPoint->y() * timerIteration / nbIteration;

        QPointF point = QPointF(x, y);
        // Send moveEvent
        e = new QMouseEvent(QEvent::MouseMove, item->mapFromItem(parentItem, point), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier );
        qDebug() << "move! " << e ;
    }else {
        //End reached, send end event
        QPointF point = QPointF(startPoint.x() + deltaPoint->x(), startPoint.y() + deltaPoint->y());
        e = new QMouseEvent(QEvent::MouseButtonRelease, item->mapFromItem(parentItem, point), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier );
        timer->stop();
        qDebug() << "end! " << e ;
    }

    qApp->postEvent(item, e);
}

所以...它没有用 . 怎么了?从我的测试:

  • 如果我删除嵌套的子部分,并直接给出交互式(拖动)QML组件(这里是嵌套的ListView),结果是好的 . 但这对我来说不是一个好的解决方案,因为我完全知道哪个组件应该做出反应 . 然而,这似乎覆盖了组件的“交互:错误”,当目的是...来测试组件时,这是一个坏主意 .

  • 鼠标区域接收所有事件 . mouseX属性已更新 . 这是一个问题 . 对于非模拟事件,MouseArea应该接收按下事件,一些移动事件,然后事件应该由ListView / Flickable捕获 . 即使最糟糕的是,即使mousePress和mouseRelease事件之间的位置不同(400px),Qt也会检测到MouseClicked事件并在QML端触发它...

所以,不知道从那里去哪里 . 我可以做一些糟糕的孩子检测(检查嵌套孩子的类型,只接受好孩子),但我对它不是很满意 . 任何的想法?

1 回答

  • 0

    好吧,所以我在QT代码中走得更深,我理解了我的错误:要正确使用sendEvent,你必须将它们传递给根视图(在我的项目中它是一个QQuickView,但它也可以是一个QWindow) . 如果你不在root上发送事件,它将不会按预期过滤mouseEvent(通过childMouseEventFilter()方法)

    我还发现MouseRelease事件需要一个NoButton参数 . 所以我的代码现在工作,看起来像这样:

    //Set mouse timer
        mouseTimer = new QTimer(this);
        mouseTimer->setInterval(m_movementDuration / m_nbIteration);
        mouseTimer->setSingleShot(false);
        connect(mouseTimer, SIGNAL(timeout()), this, SLOT(mouseMove()));
    }
    
    void xx::pressAndDrag(QObject *object, const int x, const int y, const int dx, const int dy)
    {
        m_pressAndDragCompleted = false;
    
        //Reset timer iteration
        m_timerIteration = 0;
    
        //Keep all coordinates
        startPoint = ((QQuickItem *) object)->mapToScene(QPointF(x, y));
        deltaPoint = new QPointF(dx, dy);
    
        QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress, startPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier );
        qApp->postEvent(parent(), e);
    
        //Start timer
        mouseTimer->start();
    }
    
    void xx::mouseMove()
    {
        m_timerIteration++;
        if (m_timerIteration < m_nbIteration + 2) {
            //Move mouse
            int x = startPoint.x() + deltaPoint->x() * m_timerIteration / m_nbIteration;
            int y = startPoint.y() + deltaPoint->y() * m_timerIteration / m_nbIteration;
    
            QMouseEvent *e = new QMouseEvent(QEvent::MouseMove, QPointF(x, y), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier );
    
            qApp->postEvent(parent(), e);
            // Let some time to not trigger a flick
        } else if (m_timerIteration - m_nbIteration >= 400 / mouseTimer->interval()) {
            //End movement
            QPointF point = QPointF(startPoint.x() + deltaPoint->x(), startPoint.y() + deltaPoint->y());
            QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
            qApp->postEvent(parent(), e);
    
            //Stop timer
            mouseTimer->stop();
            m_pressAndDragCompleted = true;
        }
    }
    

    如果它可以帮助 . :)

相关问题