如何在PyQt中测试拖放行为?

Ste*_*ini 8 testing qt pyqt

我想对我们的小部件进行单元测试拖放.目前,我实例化了一个QDragEnterEvent,但是不建议在Qt文档上发出重大警告,因为它依赖于Qt库内部状态.事实上,我得到的段错误似乎是由于违反了此警告.

鉴于此前提,如何测试拖放行为?

hac*_*day 5

如果使用Unix我们可以使用QTest,但是为了获得跨平台解决方案,我们可以实现一个我们绕过Qt的解决方案.

使用QTest

虽然用于拖放的Qt文档说它不会阻止主事件循环,但仔细观察QDrag.exec会发现Windows不适用.

调用QTest.mousePress导致测试阻塞,直到用户物理移动鼠标.

我通过使用计时器安排鼠标移动和释放来解决这个问题:

def testDragAndDrop(self):
    QtCore.QTimer.singleShot(100, self.dropIt)
    QtTest.QTest.mousePress(dragFromWidget, QtCore.Qt.LeftButton)

    # check for desired behaviour after drop
    assert something

def dropIt(self):
    QtTest.QTest.mouseMove(dropToWidget)
    QtTest.QTest.mouseRelease(dropToWidget, QtCore.Qt.LeftButton, delay=15)
Run Code Online (Sandbox Code Playgroud)

对于此解决方案,必须在mouseRelease调用中包含延迟,并调用show您的小部件.

请注意,我在Fedora 20上使用pyqt4和Python 2.7验证了这一点

跨平台

您可以使用PyUserInput包中的鼠标操作方法.将鼠标交互放在单独的线程中以避免锁定Qt主事件循环.我们可以这样做,因为我们在鼠标控制中根本没有使用Qt.确保您已调用show要拖动的窗口小部件.

from __future__ import division
import sys, time, threading
import numpy as np

from PyQt4 import QtGui, QtCore, QtTest
from pymouse import PyMouse
...

def mouseDrag(source, dest, rate=1000):
    """Simulate a mouse visible mouse drag from source to dest, rate is pixels/second"""
    mouse = PyMouse()
    mouse.press(*source)

    # smooth move from source to dest
    npoints = int(np.sqrt((dest[0]-source[0])**2 + (dest[1]-source[1])**2 ) / (rate/1000))
    for i in range(npoints):
        x = int(source[0] + ((dest[0]-source[0])/npoints)*i)
        y = int(source[1] + ((dest[1]-source[1])/npoints)*i)
        mouse.move(x,y)
        time.sleep(0.001)

    mouse.release(*dest)

def center(widget):
    midpoint = QtCore.QPoint(widget.width()/2, widget.height()/2)
    return widget.mapToGlobal(midpoint)

def testDragAndDrop(self):
    # grab the center of the widgets
    fromPos = center(dragFromWidget)
    toPos = center(dropToWidget)

    dragThread = threading.Thread(target=mouseDrag, args=((fromPos.x(),fromPos.y()), (toPos.x(), toPos.y())))
    dragThread.start()
    # cannot join, use non-blocking wait
    while dragThread.is_alive():
        QtTest.QTest.qWait(1000)

    # check that the drop had the desired effect
    assert dropToWidget.hasItemCount() > 0
Run Code Online (Sandbox Code Playgroud)

注意我在Fedora和Windows 7上使用PyQt4和Python 2.7对此进行了测试


seb*_*ian 0

还没有尝试过,但如果您的拖放过程是 Qt 内部的(意味着您正在从 Qt 小部件拖拽到 Qt 小部件),QTest可能会有所帮助。

基本上通过做一些事情:

QTest.mousePress(drag_widget, Qt.LeftButton) # simulate mouse press on whatever you want to drag
QTest.mouseMove(drop_widget) # move the mouse to the target - maybe this can be skipped
QTest.mouseRelease(drop_widget, Qt.LeftButton) # simulate mouse release where you want to drop
Run Code Online (Sandbox Code Playgroud)

所有功能都可以提供进一步的位置信息(例如,单击小部件内的列表项)和可选的延迟来模拟人类用户。

不是一个可复制粘贴的答案,但也许它可以作为一个开始......

  • 这不起作用 - 我已经在 Windows 8.1 和 Qt 5.4.2 上尝试过。mouseMove() 创建一个没有按钮的鼠标事件 - 这可能是问题所在。 (3认同)