[C++]Qt 如何處理密集型耗時的事情(頻繁調用QApplication::processEvents)

https://www.cnblogs.com/senior-engineer/p/5598133.htmlhtml

https://www.cnblogs.com/findumars/p/5607683.htmlapi

 

api含義:QCoreApplication::processEvents() 將處理全部事件隊列中的事件並返回給調用者。多線程

問題描述:ide

當主線程在某個槽函數里正在執行processEvents時, 恰好有一個能響應此槽函數的信號發送過來了(確定是其餘線程發的信號),  這時就可能會發生可怕的遞歸, 函數

致使棧溢出崩潰。 緣由是processEvents,進入到無盡的遞歸中。oop

示例代碼ui

bugThread.hthis

#include <QThread>
class BugThread : public QThread
{
	Q_OBJECT
public:
	BugThread(QObject* parent) : QThread(parent) {}
signals:
	void sigBugsignal();
public:
	void run() 
	{
		while(true)
		{
			emit sigBugsignal();
		}
	}
};

bugs.h & bugs.cppspa

class Bugs : public QMainWindow
{
	Q_OBJECT

public:
	Bugs(QWidget *parent = 0, Qt::WFlags flags = 0);
	~Bugs();
	public slots:
		void onBugSlot();
private:
	Ui::BugsClass ui;
};


Bugs::Bugs(QWidget *parent, Qt::WFlags flags)
	: QMainWindow(parent, flags)
{
	ui.setupUi(this);
	BugThread* bt = new BugThread(this);
	connect(bt, SIGNAL(sigBugsignal()), this, SLOT(onBugSlot()));
	bt->start();
}

Bugs::~Bugs()
{

}
void Bugs::onBugSlot()
{
	Sleep(1); 
	QApplication::processEvents();
}
===========================================================================================

有時候須要處理一些跟界面無關的但很是耗時的事情,這些事情跟界面在同一個線程中,因爲時間太長,致使界面沒法響應,處於「假死」狀態。例如:在應用程序中保存文件到硬盤上,從開始保存直到文件保存完畢,程序不響應用戶的任何操做,窗口也不會從新繪製,從而處於「沒法響應」狀態,這是一個很是糟糕的體驗 。線程

     在這種狀況下,有一種方法是使用多線程,即在子線程中處理文件保存,主線程負責界面相關。

     而若是不想使用多線程,最簡單的辦法就是在文件保存過程當中頻繁調用QApplication::processEvents()。該函數的做用是讓程序處理那些尚未處理的事件,而後再把使用權返回給調用者。

代碼以下:

複製代碼
複製代碼
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();
}
複製代碼
複製代碼

     這樣一來,程序就能響應了。

     可是,該方法有一個問題:可能正在保存文件的過程當中,用戶不當心又單擊了保存,或不當心關閉了程序主窗口,這樣會產生意想不到的後果。

     解決這個問題的最簡單的辦法是替換成:

qApp->processEvents(QEventLoop::ExcludeUserInputEvents);//它能夠忽略用戶的輸入(鼠標和鍵盤事件)。

 

     進一步的,若是想顯示一個帶有進度條的對話框,隨時顯示當前的進度狀態,能夠使用QProgressDialog。

複製代碼
複製代碼
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();
}
相關文章
相關標籤/搜索