Qt之延時總結


一、阻塞型延時
阻塞的原理就是:在延時期間,本線程的事件循環得不到執行。

1、QThread類的sleep()
最簡單的延時方法就是使用QThread類的sleep(n)、msleep(n)、usleep(n),這幾個函數的不良后果就是,GUI會在延時的時間段內失去響應,界面卡死,所以,這三個函數一般用在非GUI線程中。

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


2、使用定時器:死等

  1.  
    void Delay_MSec_Suspend(unsigned int msec)
  2.  
    {    
  3.  
        QTime _Timer = QTime::currentTime().addMSecs(msec);
  4.  
        while( QTime::currentTime() < _Timer );
  5.  
    }


二、非阻塞延時
原理無非就是利用事件循環,有兩種原理:

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

  1.  
    void Delay_MSec(unsigned int msec)
  2.  
    {
  3.  
        QTime _Timer = QTime::currentTime().addMSecs(msec);
  4.  
        while( QTime::currentTime() < _Timer )
  5.  
             QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
  6.  
    }

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

2、使用子事件循環
創建子事件循環,在子事件循環中,父事件循環仍然是可以執行的

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


三、耗時代碼的處理
假設有這樣的應用情景:點擊某個button之后,需要讀入並處理一幅圖像,需要耗時20秒才能處理完。

在這20s內,GUI會失去效應,界面上的任何元素都無法被點擊,這種情況應該怎么辦?方法有兩種:1、用另一個線程去處理這個耗時任務;2、在耗時任務中,不斷地去處理本線程的事件循環,以保證GUI的及時響應。

這里重點說一下第2種,參考https://blog.csdn.net/dbzhang800/article/details/6554104

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

 

四、Qt自帶延時

  1.  
    #include <synchapi.h>
  2.  
    synchapi.h是Qt自帶的頭文件
  3.  
     
  4.  
     
  5.  
    Sleep( 40);延遲40毫秒


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

副作用:(特別注意!)

1、在點擊按鈕之后,這個20s的耗時任務開始執行,尚未執行完畢時,我們點擊了GUI的關閉按鈕,那么GUI會立即消失,但是這個耗時任務仍然會在后台執行,直到執行完畢,進程才會退出。解決辦法:重寫關閉事件,在關閉事件的函數中直接結束進程。

2、在點擊按鈕之后,這個20s的耗時任務開始執行,執行到第5秒時,我們再次點擊了這個按鈕,那么QT又會執行一個新的20s任務,這個新任務完成后,又會接着把第一個20s任務從上次被打斷的第5秒繼續執行。如果這個任務是可重入的,后果僅僅是被執行了兩遍,如果任務不可重入,那情況就徹底糟糕了。解決辦法:點擊按鈕后把這個按鈕disable掉,執行完再enable

轉載鏈接:https://blog.csdn.net/qq_31073871/article/details/80472347 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM