1 一般我們的事件循環都是由exec()來開啟的,例如下面的例子:
1 QCoreApplicaton::exec()
2 QApplication::exec()
3 QDialog::exec()
4 QThread::exec()
5 QDrag::exec()
6 QMenu::exec()
這些都開啟了事件循環,事件循環首先是一個無限“循環”,程序在exec()里面無限循環,能讓跟在exec()后面的代碼得不到運行機會,直至程序從exec()跳出。從exec()跳出時,事件循環即被終止。QEventLoop::quit()
能夠終止事件循環。
事件循環實際上類似於一個事件隊列,對列入的事件依次的進行處理,當時間做完而時間循環沒有結束的時候,其實際上比較類似於一個不占用CPU事件的for(;;)循環。
其本質實際上是以隊列的方式來重新分配時間片。
2.事件循環是可以嵌套的,當在子事件循環中的時候,父事件循環中的事件實際上處於中斷狀態,當子循環跳出exec之后才可以執行父循環中的事件。當然,這不代表在執行子循環的時候,類似父循環中的界面響應會被中斷,因為往往子循環中也會有父循環的大部分事件,執行QMessageBox::exec(),QEventLoop::exec()的時候,雖然這些exec()打斷了main()中的QApplication::exec(),但是由於GUI界面的響應已經被包含到子循環中了,所以GUI界面依然能夠得到響應。
3.如果某個子事件循環仍然有效,但其父循環被強制跳出,此時父循環不會立即執行跳出,而是等待子事件循環跳出后,父循環才會跳出
舉幾個例子吧,比如說如果想要將主線程等待100ms,總不能使用sleep吧,那樣會導致GUI界面停止響應的,但是用事件循環就可以避免這一點:
1 QEventLoop loop;
2 QTimer::singleShot(100, &loop, SLOT(quit()));
3 loop.exec();
還有,比如說對於一個槽函數,觸發之后會彈出一個dialog,但是像下面這樣寫的話,窗口會一閃而過的:
1 void ****::mySLot{
2 QDialog dlg;
3 dlg.show();
4 }
當然這里可以使用將dlg改成一個靜態成員,通過增長期生存期的方法來解決這個問題,但是這里同樣可以使用eventLoop來解決這個問題:
1 void ****::mySLot{
2 QDialog dlg;
3 dlg.show();
4 QEventLoop loop;
5 connect(&dlg, SIGNAL(finished(int)), &loop, SLOT(quit()));
6 loop.exec(QEventLoop::ExcludeUserInputEvents);
7 }
將dlg寫入事件循環中,因為此時dlg的活動只是show,沒用調用任何資源,這種等待狀態可以與其它事件並存,其它事件仍能觸發;直到dlg發出finished信號,退出事件循環,代碼繼續向下執行。
QEventLoop
At any time, you can create a QEventLoop object and call exec() on it to start a local event loop. From within the event loop, calling exit() will force exec() to return.
退出方法
方法一:
QEventLoop loop;
...
QNetworkReply *postReply = m_pNetManager->post(request, qbt); //post方式到本地服務器
connect(postReply, SIGNAL(finished()), this, SLOT(postFileReplyFinished())); //成功后會有返回響應
loop->exec(); //設置等待,若文件成功發送,則退出等待
...
//在其他的響應函數中退出循環
void Widget::postFileReplyFinished()
{
QNetworkReply* reply = (QNetworkReply*)sender();
QByteArray replyData = reply->readAll();
//轉為JSon格式,便於提取字段數據
QJsonDocument jsonDoc= QJsonDocument::fromJson(replyData);
if(!jsonDoc.isNull())
{
QJsonObject jsonObj = jsonDoc.object(); //轉換格式
if(jsonObj.contains("status"))
{
loop->exit(); //loop退出等待
}
}
}
方法二
QEventLoop loop;
qManager = new QNetworkAccessManager(this);
QNetworkRequest request;
request.setUrl(QUrl("http://localhost/public/index/file/upload"));
QNetworkReply *reply = qManager->get(request);
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
這樣的話就更簡潔了。可是有個問題就是,一收到reply就退出事件的循環,如果想要判斷一下還是用前面的方法比較好