2016-03-03 18 views
1

我想對我的Qt應用程序做一個基本的自動化測試。它記錄鼠標事件並將它們寫入文件(f.e. mousepress(300,400))。當開始自動化時,它從文件讀取座標,發送適當的鼠標事件,並與先前保存的屏幕截圖進行像素比較。如何通過將事件發佈到Qt事件系統來模擬鼠標點擊?

目前,我有一個覆蓋小部件,跨越應用程序,並有透明的鼠標事件。它所做的就是跟蹤座標。 重新讀取數據時,該覆蓋圖會在鼠標按下位置繪製一個矩形。 發送mousePressEvents到Qt的事件系統時需要幫助。它在正確的位置繪製點,但從未實際進行物理點擊。 有沒有辦法做到這一點與Qt或我必須使用Window的SendInput()?

有沒有辦法暫停並等待鼠標事件結束?我需要知道事件何時完成才能開始逐像素比較。

Widget::Widget(QWidget *parent) 
: QFrame(parent) 
, mPoint(QPoint(0,0)) 
{ 
    setWindowFlags(Qt::WindowStaysOnTopHint); 
    setStyleSheet("background-color: rgba(0, 0,255, 2%);"); 
    setAttribute(Qt::WA_TransparentForMouseEvents, true); 
    setGeometry(parent->geometry()); 
    ... 
} 

void Widget::run() 
{ 
    QFile file("coordinates.txt", NULL); 
    if(!file.open(QIODevice::ReadOnly)) 
     return; 

    QTextStream in(&file); 
    int i = 0; 
    while (!in.atEnd()) 
    { 
     QString line = in.readLine(); 
     if(line.startsWith("mousepress")) 
     { 
      int startIndex = line.indexOf('('); 
      int endIndex = line.indexOf(')'); 

      QString coord = line.mid(startIndex+1, line.size() - startIndex - 2); 
      QStringList nbr = coord.split(','); 
      mPoint = QPoint(nbr[0].toInt(), nbr[1].toInt()); 
      QWidget *receiver = QApplication::widgetAt(mPoint); 
      QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonPress, mPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); 
      QCoreApplication::postEvent(receiver, event); // same result with sendEvent() 
      QCoreApplication::processEvents(); 
      update(); 
      // wait till the event finished, then continue with next point 
     } 
    } 
} 


void Widget::paintEvent(QPaintEvent *event) 
{ 
    QPainter p(this); 
    QPen pen; 
    pen.setBrush(Qt::NoBrush); 

    if(!mPoint.isNull()) 
    { 
    pen.setColor(Qt::red); 
    pen.setWidth(2); 
    p.setPen(pen); 

    p.drawRoundRect(mPoint.x(), mPoint.y(), 10, 10, 25, 25); 
    p.drawText(mPoint, QString::number(mPoint.x()) + ", " + QString::number(mPoint.y())); 
    } 
} 

[編輯]

我跟着ddriver的建議,並就一些修改後的作品:我保存全局和局部位置的文件,發送到QMouseEvent。

在做屏幕截圖並將其與保存的圖像進行比較之前,我怎麼能確定鼠標點擊已完成?

void Widget::DoStep() 
{ 
    if(!mInStream.atEnd()) 
    { 
     QString line = mInStream.readLine(); 
     if(line.startsWith("MouseButtonPress")) 
     { 
      QPoint pos = parseGlobalPos(); 
      QPoint localPos = parseLocalPos(); 
      QWidget *receiver = QApplication::widgetAt(pos); 

      QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonPress,localPos, pos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); 
      QApplication::postEvent(receiver, event); 
      QMouseEvent *eventRelease = new QMouseEvent(QEvent::MouseButtonRelease, localPos, pos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); 
      QApplication::postEvent(receiver, eventRelease); 

      // after successful click, take screenshot and compare them 
     } 
    } 

    if (!mInStream.atEnd()) 
     QMetaObject::invokeMethod(this, "DoStep", Qt::QueuedConnection); 
    else 
     file.close(); 
} 
+0

這可能無法完全解決這個問題,但是,您提交MouseButtonPress的事件,但你缺少一個相應的MouseButtonRelease。另外,我建議不要循環並等待事件完成,而應該爲每個事件使用單個QTimer,並讓主循環繼續運行,而不要求助於調用processEvents。 – TheDarkKnight

+0

謝謝,我試圖發佈一個額外的MouseButtonRelease事件,但沒有奏效。 – user2246120

+0

我不太清楚我的理解你的QTimer的想法。 QTimer :: singleShot(0,receiver,SlotSendEvent());無法將座標傳遞給插槽。你是什​​麼意思? – user2246120

回答

1

如果我理解正確的問題,它的來源是阻擋while循環,阻塞線程,並且不允許事件循環旋轉和處理事件。沒有辦法「暫停」,因爲它也阻止了事件循環,也無法完成工作,但是有一種方法可以一次完成一項工作,一次完成一項工作事件循環一次。

解決方案是不使用阻塞while循環,但實現事件系統驅動的循環。然後,在每個事件循環週期中處理一行,直到您耗盡工作。

移動文件,流和函數外的所有東西,使它們成爲類成員,以便它們持久化。然後在run()你只需設置爲讀取輸入,並把所有的事件發佈的東西到一個新的功能,例如doStep(),並在run()後你設置你有一個:

QMetaObject::invokeMethod(this, "doStep", Qt::QueuedConnection); 

doStep(),除了從活動的東西,到了最後,你還做調度:

if (!in.atEnd()) QMetaObject::invokeMethod(this, "doStep", Qt::QueuedConnection); 
else // we are done, close file, cleanup, whatever 

這樣只有一步將每個事件循環週期內執行,從而使事件循環旋轉並處理事件。在工作的同時,將爲下一個事件循環週期安排一個步驟。您也可以使用單次計時器來執行此操作,或者甚至可以通過排隊連接,通過發送過載事件發出完成信號來觸發。你不這樣做,也不應該強迫事件進行處理,使用這種方法將不需要。

的概念一般是約非阻塞異步事件驅動的自我調度工人,我已經發布了一個完全實現的一個here。好處是你可以跟蹤進度,暫停,取消和所有的好東西。

+0

工作:但我怎麼能確保在做截圖並將其與保存的圖像進行比較之前單擊鼠標完成?看到我編輯的問題 – user2246120

+0

@ user2246120 - 你可以做另一個排隊的調用 - 'doStep()'將安排'takeScreenshot()'和'takeScreenshot()'將安排在下一個'doStep()'。這樣所有的事件將在每個預定的調用之前處理。 – dtech

+0

另一種替代方法是從接收器的點擊事件處理程序計劃屏幕截圖。目前尚不清楚「點擊完成」的含義。我認爲這是點擊位置的繪製。所以你可以把它放在繪圖代碼之後。 – dtech

-1

嘗試發送事件QGraphicsView的視口:

qApp->sendEvent(view->viewport(), &mousePressEvent); 
+2

QWidget中沒有一個視... – user2246120

+1

這並沒有回答,甚至試圖回答這個問題。 – dtech