Как автоматизировать перетаскивание мышью с помощью pytest-qt?

У меня есть окно pyqt, которое отслеживает движение мыши, пока она нажата. Я пытаюсь написать тест для автоматизации этого движения с помощью pytest-qt.

Вот пример класса:

from PyQt5.QtWidgets import *
from PyQt5.QtGui import QCursor
from PyQt5.QtWidgets import QApplication

class Tracker(QDialog):
    def __init__(self, parent=None):
        super(Tracker, self).__init__(parent)
        self.location = None
        self.cur = QCursor()
        layout = QVBoxLayout()
        self.label = QLabel()
        layout.addWidget(self.label)
        self.setLayout(layout)
        self.setModal(True)
        self.showFullScreen()

    def mouseReleaseEvent(self, e):
        x = self.cur.pos().x()
        y = self.cur.pos().y()
        self.location = (x, y)
        return super().mouseReleaseEvent(e)

    def mouseMoveEvent(self, e):
        x = self.cur.pos().x()
        y = self.cur.pos().y()
        self.label.setText(f'x: {x}, y: {y}')
        return super().mouseMoveEvent(e)

if __name__ == '__main__':

    import sys

    app = QApplication(sys.argv)
    window = Tracker()
    sys.exit(app.exec_())

Я хотел бы написать тестовый пример, который открывает окно, затем перетаскивает мышь на 100 пикселей вправо и отпускает.

Вот что я пробовал:

track = Tracker()
qtbot.mousePress(track, QtCore.Qt.LeftButton, pos=QPoint(300, 300))
qtbot.mouseMove(track, pos=QPoint(400, 300))
qtbot.mouseRelease(track, QtCore.Qt.LeftButton)
assert track.location == (400, 300)

Я также пробовал использовать pyautogui:

track = Tracker()
x, y = pyautogui.position()
pyautogui.dragTo(x + 100, y, button='left')
assert track.location == (x + 100, y)

При запуске теста появляется, что левая кнопка мыши не удерживается при перетаскивании. Метка не будет обновляться, а атрибут местоположения не изменится.


person Evan Brittain    schedule 28.11.2019    source источник
comment
В чем проблема ваших попыток? Ваш вопрос не ясен.   -  person eyllanesc    schedule 28.11.2019
comment
Левая кнопка не удерживается, потому что метка не обновляется, а атрибут местоположения класса не изменяется.   -  person Evan Brittain    schedule 28.11.2019


Ответы (1)


- Использование qtbot.mouseMove():

pytest-qt создает оболочку QtTest, то есть функция qtbot.mouseMove() аналогична QTest::mouseMove(). И эта функция имеет ошибку, о которой сообщается QTBUG-5232, которая будет исправлена ​​в Qt6. /PyQt6, в комментариях к отчету есть несколько обходных путей, которые должны заменить эту функцию, эмулируя QMouseEvent, который не заставит курсор двигаться, но если он вызовет метод mouseMoveEvent, так что для правильной работы вам придется изменить свой код.

from PyQt5.QtWidgets import QApplication, QDialog, QLabel, QVBoxLayout


class Tracker(QDialog):
    def __init__(self, parent=None):
        super(Tracker, self).__init__(parent)
        self.location = None
        self.label = QLabel()

        layout = QVBoxLayout(self)
        layout.addWidget(self.label)
        self.setModal(True)
        self.showFullScreen()

    def mouseReleaseEvent(self, e):
        pos = self.mapToGlobal(e.pos())
        self.location = pos.x(), pos.y()
        return super().mouseReleaseEvent(e)

    def mouseMoveEvent(self, e):
        pos = self.mapToGlobal(e.pos())
        self.label.setText(f"x: {pos.x()}, y: {pos.y()}")
        return super().mouseMoveEvent(e)


if __name__ == "__main__":

    import sys

    app = QApplication(sys.argv)
    window = Tracker()
    sys.exit(app.exec_())
def test_emulate_QMouseEvent(qtbot):
    start_pos, end_pos = QtCore.QPoint(300, 300), QtCore.QPoint(400, 300)

    track = Tracker()

    def on_value_changed(value):
        event = QtGui.QMouseEvent(
            QtCore.QEvent.MouseMove,
            value,
            QtCore.Qt.NoButton,
            QtCore.Qt.LeftButton,
            QtCore.Qt.NoModifier,
        )
        QtCore.QCoreApplication.sendEvent(track, event)

    animation = QtCore.QVariantAnimation(
        startValue=start_pos, endValue=end_pos, duration=5000
    )
    qtbot.mousePress(track, QtCore.Qt.LeftButton, pos=QtCore.QPoint(300, 300))
    animation.valueChanged.connect(on_value_changed)
    with qtbot.waitSignal(animation.finished, timeout=10000):
        animation.start()
    qtbot.mouseRelease(track, QtCore.Qt.LeftButton)
    track.location == (end_pos.x(), end_pos.y())

- Использование pyautogui:

При использовании этого метода нет необходимости вносить какие-либо изменения.

def test_pyautogui(qtbot):
    start_pos, end_pos = QtCore.QPoint(300, 300), QtCore.QPoint(400, 300)
    track = Tracker()
    qtbot.waitUntil(track.isVisible)

    def on_value_changed(value):
        pyautogui.dragTo(value.x(), value.y(), button="left")

    animation = QtCore.QVariantAnimation(
        startValue=start_pos, endValue=end_pos, duration=5000
    )
    pyautogui.moveTo(start_pos.x(), start_pos.y())
    pyautogui.mouseDown(button="left")
    animation.valueChanged.connect(on_value_changed)
    with qtbot.waitSignal(animation.finished, timeout=10000):
        animation.start()

    track.location == (end_pos.x(), end_pos.y())
person eyllanesc    schedule 28.11.2019