如何使用 pytest-qt 自动拖动鼠标?

Posted

技术标签:

【中文标题】如何使用 pytest-qt 自动拖动鼠标?【英文标题】:How to automate mouse drag using pytest-qt? 【发布时间】:2019-11-28 00:15:22 【问题描述】:

我有一个 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)

运行测试时,鼠标左键在拖动时似乎没有按住。标签不会更新,位置属性不会改变。

【问题讨论】:

您的尝试有什么问题?您的问题不清楚。 左键似乎没有被按住,因为标签没有更新并且类的位置属性没有改变。 【参考方案1】:

- 使用qtbot.mouseMove():

pytest-qt 对 QtTest 做了一个封装,即函数 qtbot.mouseMove() 与QTest::mouseMove() 相同。并且这个函数有一个报告的错误QTBUG-5232 将在 Qt6/PyQt6 中修复,在报告的 cmets 中有几个解决方法是通过模拟不会使光标移动的 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())

【讨论】:

以上是关于如何使用 pytest-qt 自动拖动鼠标?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 pytest-qt 中处理模态对话框而不模拟对话框

WPF C#如何使用鼠标使控件可拖动

flash window组件 如何使其禁止拖动

如何使禁用的控件允许鼠标拖动或移动?

鼠标拖动文字或者图片,浏览器自动新建页面打开。如何关闭此功能!

在opengl中,如何将鼠标跟随更改为鼠标单击、拖动和释放?