我正在研究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端触发它......
所以,不知道从哪里去。我可以做一些糟糕的孩子检测(检查嵌套孩子的类型,只接受好孩子),但我对它不是很满意。有什么想法吗?
答案 0 :(得分: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;
}
}
如果可以提供帮助。 :)