QT——延時問題的彙總

QT延時/等待怎麼寫?大概分爲兩類,一個是非阻塞延時,一個是阻塞延時,這裏做一個小結,第三種耗時方法用的較少


一、阻塞型延時
Qt一般使用QThread::sleep()來延時,但是這樣會阻塞住線程,體驗太差,這樣只可以用在子線程中。

QThread::msleep(50);//阻塞延時50ms

或者使用定時器:

void Delay_MSec_Suspend(unsigned int msec)
{    
    QTime _Timer = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < _Timer );
}

二、非阻塞型延時
在等待中,不斷強制進入當前線程的事件循環,這樣可以把堵塞的事件都處理掉,從而避免程序卡死
可以處理本線程的事件循環

void Widget::sleep(unsigned int msec)
{
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < dieTime )
        {
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
        //這條語句能夠使程序在while等待期間,去處理一下本線程的事件循環,處理事件循環最多100ms必須返回本語句,
        //如果提前處理完畢,則立即返回這條語句。這也就導致了該Delay_MSec函數的定時誤差可能高達100ms。
    }
      
}

或者使用子事件循環,在子事件循環中,父事件循環仍然是可以執行的

void Delay_MSec(unsigned int msec)
{
    QEventLoop loop;//定義一個新的事件循環
    QTimer::singleShot(msec, &loop, SLOT(quit()));//創建單次定時器,槽函數爲事件循環的退出函數
    loop.exec();//事件循環開始執行,程序會卡在這裏,直到定時時間到,本循環被退出
}

三、耗時代碼
例如後臺需要載入圖片,GUI響應太卡,可以使用這種方法

for(i=0; i < 1000000; i++)
{
    //QCoreApplication::processEvents(QEventLoop::AllEvents);    
    //去處理本線程的事件循環,避免本線程被堵塞
    QCoreApplication::processEvents(QEventLoop::AllEvents, 5);
    //如果不夠頻繁,可以增加第二參數來緩解卡頓
 
    for(j=0; j < 1000000; j++)
    {
        //QCoreApplication::processEvents(QEventLoop::AllEvents);
        //處理事件循環,不建議放在這裏,可能過於頻繁
        doSomeThing();
    }
}

一般來說,processEvents()不宜被調用的過於頻繁,也不宜被調用的不夠頻繁。過於頻繁的話,一方面會使線程的響應更好,但另一方面會導致原本就耗時的任務變得更加耗時;不夠頻繁的話,顯然可能會使GUI線程的響應變差,例如每500ms才被調用一次,那麼GUI的事件循環就只能500ms才被處理一次,當然,這個問題可以通過設定processEvents()的第二個形參略微得到緩解,更好的做法是,保證被調的週期<200ms(再小一些更好,看程序需求),這樣不至於肉眼可見的卡頓。

副作用:(特別注意!)

1、在點擊按鈕之後,這個20s的耗時任務開始執行,尚未執行完畢時,我們點擊了GUI的關閉按鈕,那麼GUI會立即消失,但是這個耗時任務仍然會在後臺執行,直到執行完畢,進程纔會退出。解決辦法:重寫關閉事件,在關閉事件的函數中直接結束進程。
2、在點擊按鈕之後,這個20s的耗時任務開始執行,執行到第5秒時,我們再次點擊了這個按鈕,那麼QT又會執行一個新的20s任務,這個新任務完成後,又會接着把第一個20s任務從上次被打斷的第5秒繼續執行。如果這個任務是可重入的,後果僅僅是被執行了兩遍,如果任務不可重入,那情況就徹底糟糕了。解決辦法:點擊按鈕後把這個按鈕disable掉,執行完再enable

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章