2017-07-17 93 views
0

我寫一個C++ QT5 Widget桌面應用程序中的QT主窗口方法,我需要運行時間被壓在一個單獨的線程時,起動/停止按鈕耗時的操作MainWindow::performLengthyOperation(bool)運行在單獨的線程

這耗時的操作是在我的MainWindow.h/CPP一個相當長的方法。停止後臺IO活動的操作大約需要6秒,啓動大約需要2秒。在按下開始/停止按鈕的過程中,UI不響應。本質上,在附加到我的按鈕單擊事件的插槽中,我需要執行以下邏輯。

void 
MainWindow::on_pushButtonStart_clicked(bool checked) 
{ 
    // temporarily disable the pushbutton 
    // until the lengthy operation completes 
    mUI->pushButtonStart->setEnabled(false); 

    if (checked) { 
     // Start the timer tick callback 
     mTickTimer.start(APP_TICK, this); 
     mUI->pushButtonStart->setText("starting..."); 

     // This method needs to somehow run in its own QT thread 
     // and when finished, call a slot in this MainWindow to 
     // re-enable the pushButtonStart and change the statusBar 
     // to indicate "runing..." 
     performLengthyOperation(true); 
     //mUI->pushButtonStart->setText("Stop") 
     //mUI->statusBar->setStyleSheet("color: blue"); 
     //mUI->statusBar->showMessage("runing..."); 
    } else { // Stop the protocol threads 
     // Stop the subsystem protocol tick timer 
     mTickTimer.stop(); 
     mUI->pushButtonStart->setText("stopping..."); 
     // This method needs to somehow run in its own QT thread 
     // and when finished, call a slot in this MainWindow to 
     // re-enable the pushButtonStart and change the statusBar 
     // to indicate "ready..." 
     performLengthyOperation(false); 
     // finally toggle the UI controls 
     //mUI->pushButtonStart->setText("Start") 
     //mUI->statusBar->setStyleSheet("color: blue"); 
     //mUI->statusBar->showMessage("ready..."); 
    } 
} 

當我正在尋找的例子就如何做到這一點,我在整個following article來了,但我有麻煩它適應我的方案,我需要以某種方式獲得主窗口到工人,因此它可以訪問它的UI小部件等,這似乎有點矯枉過正。

我非常想找一個簡單的方法來異步運行lambda函數,我可以把這些耗時的操作(在主窗口作爲參數傳遞)。這比使用QThreads和將對象移動到線程等更爲可取。但我對QT框架知之甚少,無法確定這是否安全或可行。

+0

即使您傳入窗口,也無法從其他線程處理它。你需要將這些操作歸爲主線程(儘管我認爲Qt可以通過信號/插槽來完成)。 – Steve

回答

1

使用的std ::異步和lambda表達式:

添加std::future<void> future;作爲成員到你的主窗口類。

添加槽OnLengthyOperationPerformed與代碼:

mUI->pushButtonStart->setText("Stop") 
mUI->statusBar->setStyleSheet("color: blue"); 
mUI->statusBar->showMessage("runing..."); 
mUI->pushButtonStart->setEnabled(true); 

添加信號void LengthOperationPerformed();,並將其與在主窗口構造槽連接。通過Qt::QueuedConnection作爲連接的第五個參數,因爲您想從主線程調用您的插槽。

然後在on_pushButtonStart_clicked方法,你可以這樣寫:

future = std::async(std::launch::async, [this] { 
    performLengthyOperation(true); 
    emit LengthOperationPerformed(); 
}); 

與其他呼叫一樣。只需添加另一個插槽並將信號或通過標誌插入插槽。

朗動作將在另一個線程中運行,當它完成主窗口接收信號,並重新啓用按鈕。

+0

爲了啓動呼叫未來的線程:: get() – johnco3

+0

沒有人。將來不需要存儲價值。 –

+0

感謝,使用構造函數中的下列連接語法連接(這一點,SIGNAL(LengthyMethodPerformed(常量布爾)),這一點,SLOT(updateStartStopButton(常量QString的&)),QT :: QueuedConnection);做連接後,但是...我獲取qt_message_fatal錯誤:QCoreApplication :: sendEvent中的ASSERT失敗:「無法將事件發送給其他線程擁有的對象,當前線程34e6b60。接收者'(類型'QSerialPort')是在線程40c460中創建的。 – johnco3

相關問題