有時候須要處理一些跟界面無關的但很是耗時的事情,這些事情跟界面在同一個線程中,因爲時間太長,致使界面沒法響應,處於「假死」狀態。例如:在應用程序中保存文件到硬盤上,從開始保存直到文件保存完畢,程序不響應用戶的任何操做,窗口也不會從新繪製,從而處於「沒法響應」狀態,這是一個很是糟糕的體驗 。多線程
在這種狀況下,有一種方法是使用多線程,即在子線程中處理文件保存,主線程負責界面相關。ide
而若是不想使用多線程,最簡單的辦法就是在文件保存過程當中頻繁調用QApplication::processEvents()。該函數的做用是讓程序處理那些尚未處理的事件,而後再把使用權返回給調用者。函數
代碼以下:oop
bool MyApp::writeFile(const QString &filename) { QFile file(filename); ... QApplication::setOverrideCursor(Qt::WaitCursor); for(int r = 0; r != rowCount; ++r) { for(int c = 0; c != colCount; ++c) { out << table(r,c); qApp.processEvents(); } } QApplication::restoreOverrideCursor(); }
這樣一來,程序就能響應了。spa
可是,該方法有一個問題:可能正在保存文件的過程當中,用戶不當心又單擊了保存,或不當心關閉了程序主窗口,這樣會產生意想不到的後果。線程
解決這個問題的最簡單的辦法是替換成:rest
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);//它能夠忽略用戶的輸入(鼠標和鍵盤事件)。
進一步的,若是想顯示一個帶有進度條的對話框,隨時顯示當前的進度狀態,可使用QProgressDialog。code
bool MyApp::writeFile(const QString &filename) { QFile file(filename); ... QApplication::setOverrideCursor(Qt::WaitCursor); QProgressDialog progress; progress.setWindowTitle(tableData->sNameCH); progress.setLabelText(QStringLiteral("數據保存中,請稍候...")); //progress.setCancelButton(0);//不顯示「取消」按鈕 progress.setCancelButtonText("取消"); progress.setRange(0,rowCount ); progress.setModal(true); //此處沒有調用show()來顯示,是由於QProgressDialog會自動決定是否顯示 //若是時間太短,就不會顯示。 for(int r = 0; r != rowCount; ++r) { progress.setValue(row); //若是用戶單擊了「取消」,就取消保存文件,並刪除該文件。 if(progress.wasCanceled) { file.remov(); return false; } for(int c = 0; c != colCount; ++c) { out << table(r,c); qApp.processEvents(); } } QApplication::restoreOverrideCursor(); }
顯示效果以下:blog