Как имитировать перетаскивание с помощью QTest

Чтобы создать тестовый пример для ошибки перетаскивания в QTreeView виджет Я попытался смоделировать поведение мыши при перетаскивании.

Я в основном выбираю первый элемент в QTreeViewи хотите перетащить его на третий элемент. Я сделал это, используя комбинациюQTest::mousePress а также QTest::mouseMove. В конце, конечно, должен бытьQTest::mouseRelease, но мне уже не удалось воспроизвести mousePress и mouseMove.

Это шаги, необходимые для воспроизведения:

  1. Пользователь перемещает мышь в центр первого элемента
  2. Пользователь нажимает левую кнопку мыши
  3. Пользователь, удерживая левую кнопку мыши нажатой, перемещает мышь в центр третьего элемента.
  4. Пользователь отпускает левую кнопку мыши

Если выполнить эти действия, как описано, я вижу, что QTreeView Виджеты реагируют соответствующим образом и указывают специальные выделения и вертикальные линии на случай, если элемент будет перемещаться между элементами.

К сожалению, мой автоматизированный тест не может воспроизвести это поведение. Кажется, что звонитQTest::mousePressпоследовательно делает что-то другое. Также с помощью парыQTest::mousePress а также QTest::mouseMove это что-то другое.

Это мой код:

main.cpp

#include "TestObject.h"
#include <QTest>

QTEST_MAIN(TestObject)

TestObject.h

#include <QtTest/QtTest>

class TestObject : public QObject
{
    Q_OBJECT

private slots:
    void dragAndDrop();
};

TestObject.cpp

#include "TestObject.h"
#include "TestObject.moc"
#include <QTest>
#include <QTreeView>
#include <QStandardItemModel>
#include <QPropertyAnimation>
#include "MouseMover.h"

void TestObject::dragAndDrop() {
    qDebug() << "Hello";
    QStandardItemModel model;
    QTreeView view;
    view.setModel(&model);
    view.show();
    view.setHeaderHidden(true);
    view.setDragDropMode(QAbstractItemView::DragDropMode::DragDrop);
    view.setDefaultDropAction(Qt::DropAction::MoveAction);
    view.setColumnHidden(1, true);
    for (auto rowIter = 0; rowIter < 3; rowIter++) {
        QList<QStandardItem*> items;
        for (auto colIter = 0; colIter < 2; colIter++) {
            items << new QStandardItem(QString("%1-%2").arg(rowIter).arg(colIter));
        }
        model.appendRow(items);
    }

    MouseMover mover;
    mover.setWidget(view.viewport());
    QPropertyAnimation anim(&mover, "mousePosition");

    QTimer::singleShot(0, [&]() {
        auto startValue = view.visualRect(model.index(0, 0)).center();
        auto endValue = view.visualRect(model.index(2, 0)).center();

        QTest::mousePress(view.viewport(), Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier, startValue);
        anim.setStartValue(startValue);
        anim.setEndValue(endValue);
        anim.setDuration(500);
        anim.start();
    });
    qApp->exec();
}

MouseMover.h

#pragma once
#include <QObject>
#include <QTest>

class MouseMover : public QObject {
Q_OBJECT
public:
    Q_PROPERTY(QPoint mousePosition READ mousePosition WRITE setMousePosition MEMBER mMousePosition)

    void setWidget(QWidget* widget) {
        mWidget = widget;
    }
    QPoint mousePosition() const {
        return mMousePosition;
    }

    void setMousePosition(const QPoint& pos) {
        mMousePosition = pos;
        if (mWidget) {
            QTest::mousePress(mWidget, Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier, mMousePosition);
            QTest::mouseMove(mWidget, mMousePosition);

        }
    }

private:
    QPoint mMousePosition;
    QWidget* mWidget{ nullptr };
};

MouseMover.cpp

#include "MouseMover.h"

1 ответ

mouseMoveEvent()обработчик запускается и блокируется вQDrag.exec(). Чтобы имитировать падение, вы должны запланировать его, например, с помощьюQTimer:

      def complete_qdrag_exec():
    QTest.mouseMove(drop_target)
    QTest.qWait(50)
    QTest.mouseClick(drop_target, Qt.MouseButton.LeftButton)

QTimer.singleShot(1000, complete_qdrag_exec)
QTest.mousePress(drag_source, Qt.MouseButton.LeftButton, Qt.KeyboardModifier.NoModifier, QPoint(10, 10))
QTest.mouseMove(drag_source, QPoint(50, 50))  # Ensure distance sufficient for DND start threshold

Выше показан простой Python (PyQt6/PySide6). Я предполагаю, что это похоже на C++...

Другие вопросы по тегам