保持Qt GUI響應的幾種方法

最開始使用Qt時就遇到過QT Gui失去響應的問題,我是用多線程的方式解決的,然而一般來講,多線程是會下降程序的運行速度。html

以後,在使用QSqlQuery::execBatch()函數時,Qt Gui 又失去響應,雖然多線程能夠解決,可是若是能用單線程很好解決的,最好不要用到多線程,由於多線程不只容易拖慢程序的速度,編程及維護的難度也更大,能用簡單方法解決的,就不要用複雜的方法。sql

因而我再次搜索資料,指望在解決方案的選擇與解決步驟上,可以獲得一個全面而又細緻的總結。編程

 

因此本文是在此文基礎上的部分翻譯、理解與二次總結。總之,有刪減,有補充,因此沒寫 '轉' 字。服務器

1、問題的來源與分析網絡

     首先,咱們要知道 「爲何Qt Gui 會中止響應?」。簡明扼要的說就是:長時間的密集處理或等待阻塞了Qt的事件循環,應用程序不能響應來自窗口系統的事件請求(《C++ Gui Qt4》 P135中有描述)。   那麼多長算長呢?一秒鐘算長,兩秒鐘太長。多線程

     其次,「 何種情形下會發生該問題? 」。可分爲兩種情形:框架

     第一,長時間按順序執行的密集運算,所有計算結束後才能繼續執行,如快速傅立葉變換。異步

     第二,「 觸發 」了某項操做,該操做完成後才能進行「 下一步 」, 因此這裏描述的是異步操做,如保存文件操做,服務器等待鏈接、網絡下載等。詳細見附註(1).函數

     私覺得兩種情形並沒有明顯的概念上的區分,本質是同樣的,但兩種情形有不一樣的處理方法,特別是第二種情形, 在Qt框架下 ,用Qt的信號和槽機制每每能夠解決阻塞問題,如QTcpServer::newConnection信號通知鏈接的到來,QIODevice::bytesWritten()與 QIODevice::readyRead()通知文件的讀寫,它們都是以非阻塞的形式實現相關功能的利器。 而第一種情形,不只全部的事件循環中止了,信號和槽也暫時被忽視。咱們將針對以上兩種情形尋找解決方案。oop

     最後,咱們考慮是否能夠把這個形成 Qt Gui 中止響應的罪魁禍首大卸八塊,即把他拆分紅一個個小塊,若是能夠拆分,那麼每塊之間是依賴仍是獨立,若是獨立那問題好辦,放在不一樣的位置獨立運做,不然,咱們只能同步的執行,而最差的結果是——根本沒法拆分!!

     總之,考慮以上信息差別,執行不一樣的解決方案。

2、解決方案

Manual event processing(人工執行事件)

     保持事件循環有一種最基本的方法——讓程序去處理 懸掛事件好了 ,處理完了再回來繼續個人後續運算,要作到這一點,就要在個人運算代碼中間加上處理事件的代碼,這句代碼就是 QCoreApplication::processEvents();,只要該句代碼可以週期性的被執行,就能保持Qt Gui的響應。

//代碼來源於上述連接所指向文章

複製代碼

for (int i = 3; i <= sqrt(x) && isPrime; i += 2) {
        label->setText(tr("Checking %1...").arg(i));
        if (x % i == 0)
            isPrime = false;
        QCoreApplication::processEvents();
        if (!pushButton->isChecked()) {
            label->setText(tr("Aborted"));
            return;
        } 

    }

複製代碼

部分翻譯(略)——可查看 Jason Lee的翻譯

     該方案除了 具備Witold Wysota文中 所提到缺點以外,《C++ Gui Qt4》P135中還提到,用戶可能會在應用程序還在執行某種操做時,或者關閉了主窗口,或者經過界面再次觸發相同操做,這樣就會產生不可預料的後果,如 一個保存文件對話框,用戶單擊save按鈕後,程序開始磁盤文件的寫入操做,該操做還未完成時,用戶再次單擊了關閉按鈕,或者再次單擊save按鈕。書中給出的解決辦法是將 qApp->processEvents()替換爲qApp-> processEvents(QEventLoop::ExcludeUserInputEvents),以告訴Qt忽略鼠標事件和鍵盤事件。

相關文章
相關標籤/搜索