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控件显示。

这里写图片描述

这里写图片描述

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