QT多線程—主界面卡死解決方案

由於耗時的操作會獨佔系統cpu資源 ,讓界面卡死在那裏,這時需要考慮多線程方案,將耗時的操作放在主線程之外的線程中執行。
但是必須注意:主界面更新只能在主線程中,耗時操作可以放在新建的線程中。

(1) 嘗試方案一 (沒效果)
不採用多線程,考慮其替代方案。經過試驗沒有效果,不知道問題出在哪裏,還需要深入學習。

    QElapsedTimer et;
    et.start();
    while(et.elapsed() < 100)
     QCoreApplication::processEvents();//沒效果

(2) 嘗試方案二(沒效果)
創建一個線程,子類化QThread並且重寫它的run()函數,

class MyThread : public QThread
{
     Q_OBJECT
protected:
     void run();
};
void MyThread::run()
{
     ...
}

這裏還碰到一個很奇怪的問題,通過start()函數執行該線程,有時候能進入run()函數,有時候不能進入run()函數,現在記錄下這個問題,留待深入學習。

(3) 解決方案(有效果)
通過QObject::moveToThread()函數創建新線程,使用這種方法可以很容易地將一些費時的操作放到單獨的工作線程中來完成。可以將不同線程間的信號和槽進行關聯,而且這種關聯是安全的。
在執行耗時操作過程中,通過進度對話框(QProgressDialog)和定時器(QTimer)來提示用戶:耗時操作正在進行中。

該demo源代碼可以在這裏下載,不需要積分!
http://download.csdn.net/detail/learn_sunzhuli/8757715

部分代碼如下:

multiThreadTest::multiThreadTest(QWidget *parent, Qt::WFlags flags)
    : QWidget(parent, flags),
    ui(new Ui::multiThreadTestClass)
{
    ui->setupUi(this);

    retinalLayerVisualization* visua = new retinalLayerVisualization;
    visua->moveToThread(&visuaThread);
    visua->resultQVTKViewer = ui->qvtkWidget;
    connect(&visuaThread, SIGNAL(finished()), visua, SLOT(deleteLater()));
    connect(ui->visualizationButton, SIGNAL(clicked()), visua, SLOT(doVisualization()));
    connect(visua, SIGNAL(returnResult(vtkRenderer*)), this, SLOT(updateViewer(vtkRenderer*)));
    visuaThread.start();

    progDlg = new QProgressDialog();
    progDlg->setWindowTitle("Please wait..."); 
    progDlg->setFixedWidth(300);
    progDlg->setRange(0, 100);
    progDlg->show();
    timer = new QTimer();
    currentValue = 0;
    progDlg->setValue(currentValue);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateProgressDialog()));
    timer->start(100);//開啓一個沒有終點的定時器
}

void multiThreadTest::updateViewer(vtkRenderer* renderer)
{
    vtkRenderWindow* renwin = vtkRenderWindow::New();
    renwin->AddRenderer(renderer);
    vtkRenderWindowInteractor* resultRenWinInteractor = vtkRenderWindowInteractor::New();
    resultRenWinInteractor->SetRenderWindow(renwin);
    ui->qvtkWidget->GetRenderWindow()->AddRenderer(renderer);
    ui->qvtkWidget->GetRenderWindow()->SetInteractor(resultRenWinInteractor);
    ui->qvtkWidget->GetRenderWindow()->Render();//主線程更新UI
    timer->stop();
    if(currentValue != 100)
        currentValue = 100;
    progDlg->setValue(currentValue);
    delete progDlg;
}

void multiThreadTest::updateProgressDialog()
{
    currentValue++;  
    if( currentValue == 100 )  
        currentValue = 0;  
    progDlg ->setValue(currentValue);
    QCoreApplication::processEvents();//避免界面凍結
    if(progDlg->wasCanceled())
        progDlg->setHidden(true);//隱藏對話框
}

該demo運行結果圖,第一個爲進度對話框;第二個爲視網膜可視化圖,該視圖通過VTK體繪製得到,通過QVTKWidget控件顯示。

這裏寫圖片描述

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章