2013-01-18 70 views
1

我已經從循環(它進行一些計算)發出信號觸發進度條更新位於主GUI上,循環結束後進度條更新爲100%(進度條變爲當進程結束時隱藏),但比延遲時間長,進度條保持100%,並且有時鼠標變爲繁忙狀態,並且只有在幾秒鐘後進度條纔會隱藏(表明延遲結束),在那個循環之後沒有任何東西,所以我能想到的任何東西都可以使這個延遲。QProgressBar完成加載後無法解釋的延遲

  • 我應該注意到,如果循環計算是輕的(意思是不需要進行大量的計算),那麼就沒有這樣的延遲。

的發出信號是在邏輯層在類中,我有包括<QtGui/QApplication>成類(的聲音,我不應該做的事情試一下,因爲這是邏輯層,它爲什麼要需要QtGui庫,但我只測試一些東西),我把下面的代碼qApp->processEvents();放在循環中,現在事情似乎窒息,沒有忙的鼠標,但仍然有一個延遲(唯一不同的是我可以與圖形用戶界面,雖然這種延遲發生,但沒有更新的結果,直到這個延遲結束)。

由於測試processEvents()我認爲它是與線程相關的東西,但如果是這樣的話,我該如何糾正延遲行爲,當然如果有人認爲它可能是別的東西,請告訴。

一些示例代碼:

邏輯層類:

#include <QtGui/QApplication> 
... 

processMethod(...) 
{ 
    Loop(...) 
    { 
     qApp->processEvents(); 
     emit processBarSignle(value); 
     ...some calculations... 
    } 
    emit processBarSignle(100); 
} 

View層(主窗口):

on_btn_nextProcess_clicked() 
{ 
    m_ui->pBar_process->setVisible(true); 
    LogicClass->processMethod(...); 
    m_ui->pBar_process->setVisible(false); 
} 

由於

回答

0

嘗試以下方法:

#include <QtCore/QCoreApplication> 
... 

processMethod(...) 
{ 
    Loop(...) 
    { 
     emit processBarSignle(value); 
     QCoreApplication::processEvents(); 
     ...some calculations... 
    } 
    emit processBarSignle(100); 
    QCoreApplication::processEvents(); 
} 

processEvents()QCoreApplication的靜態方法,就像僅包含作爲QtCore庫的一部分的QCoreApplication就足夠了。

此外,您應該在進度條更新後添加processEvents(),而不是在此之前。

請注意,processEvents()不會返回,直到處理了Qt的事件隊列中的每個事件。如果有例如一個Cancel按鈕,您將不得不檢查用戶是否真的取消了每次您撥打processEvents()時的操作。
您可以通過使用

QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents) 

排除用戶特定的事件,如鼠標點擊/按鍵,但將不會允許任何點擊(例如取消按鈕),而循環是有效的。

作爲再一注:這應該叫「processBarSi NG樂」 ;-)


上線等澄清:

你的整個循環,任何鼠標點擊等被執行只有一個線程。如果您撥打emit(),則連接到該signalslot立即執行(,除非該插槽實際上位於不同的線程中)。同時,循環不會繼續!

當插槽完成後,您的循環將繼續。在我的例子中,這意味着processEvents()將被調用。現在,如果您的插槽更新了進度條或執行了其他任何會導致重新繪製的事件,則會在事件隊列中出現重新繪製事件,並且現在會進行重新繪製。
如果您在呼叫您的插槽之前執行processEvents(),則此時不會有重繪事件可以處理。

再次,循環不會繼續,直到processEvents()完成。處理完所有待處理事件後,循環會繼續進行計算。

+0

你的方法仍然存在延遲(我認爲延遲較少,但很難說)。 – GoldenAxe

0

在你的代碼示例中,實際上只有一個線程。當調用on_btn_nextProcess_clicked()時,它顯示進度條,然後在同一個線程中運行processMethod()。理想情況下,你想分開你的用戶界面和數據處理邏輯。

在初始化中,創建一個單獨的QThread,啓動它,並通過調用logicClassObject-> moveToThread([您的新線程])將您的LogicClass對象移動到該線程。然後,將processMethod()插入一個插槽,在MainWindow中創建一個startProcessing()信號並將它們連接起來。最後,在MainWindow中創建一個processingDone()插槽,並在LogicClass中創建一個finishedProcessing()插槽並連接它們。當這一切設置你可以改變你的代碼如下:

void LogicClass::processMethod(...) 
{ 
    Loop(...) 
    { 
     emit processBarSignal(value); 
     ...some calculations... 
    } 
    emit processingDone(); 
} 

void MainWindow::on_btn_nextProcess_clicked() 
{ 
    m_ui->pBar_process->setVisible(true); 
    emit startProcessing(...); 
} 

void MainWindow::finishedProcessing() 
{ 
    m_ui->pBar_process->setVisible(false); 
} 

每當你從兩個獨立的線程連接信號和槽,多線程採取的自動處理。在一個線程中發出信號會導致一個事件在另一個線程重新獲得控制權後纔會調用該插槽。

在這種情況下,UI線程將安排處理線程中的事件開始處理。處理線程將不斷調度progressBar值更新,並最終計劃一個事件以在完成時關閉進度條。這兩個線程將根據操作系統線程調度程序運行,並且處理不會阻止用戶界面。

+0

我應該使用相同的方法分離UI和QGraphicsView嗎? – GoldenAxe

+0

QGraphicsView是UI的一部分,需要在UI線程中。如果你將它移出,你會得到錯誤。你想要移出UI線程的任何重要處理都需要完成,以作爲設置QGraphicsScene的先決條件。 – Joey

+0

順便說一句,我建議你結帳Maya Posch關於[「如何真的,真正使用QThreads」]的精彩討論(http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use -qthreads最全的解釋/) – Joey