来源: http://m.blog.csdn.net/blog/wangyifei0822/2456147 http://hi.baidu.com/chb_seaok/item/98f8c130c9c662b0633aff0b
在GUI编程中,一个老生常谈的问题是,如何在程序繁忙的时候仍然保证程序能够响应用户输入。当一个信号处理函数在进行长时间的处理的时候,界面的确是无 法响应或者重绘的,这个是QT本身的机制决定的。例如,用户点击了“保存文件”的菜单,程序进入了保存的历程,这个过程往往会比较耗时,如果碰上IO问题 那么程序很可能就卡住无法响应了,而用户此时可能会试图取消这个保存的过程。这个问题在QT-4中可以有如下的几种解决方式:
1 调用QApplication::processEvents()。在信号处理函数中多调用几次这个静态函数,强制应用程序响应和重绘,例如:
void btn_Clicked() {
// 一些处理……
QApplication::processEvents();
// 继续进行另外一些处理……
QApplication::processEvents();
// 继续……
}
这个方法的好处是简单易用,缺点是不能实时响应改变,有一定的小延时,而且开发人员要时刻想到调用这个方法。
2 使用QThread类进行多线程处理操作,这个方法的优点很明显,就是实时性好,但是实现起来可能会比较麻烦。
3 使用QTimer类,响应计时器事件来重绘界面。这个方法的原理是应用程序不会一直在工作,可能时不时地会有空闲时间,那么可以利用定时器的方式,在程序 空闲的时候重绘界面,只要将定时器的倒数时间定为0就可以了,这样只要程序一空闲,就会响应定时器事件,重绘界面。这个方法的优点是把界面重绘工作交给应 用程序去做无需编程人员干预,缺点也很明显,实时性不高,不一定什么时候应用程序会空闲,能够响应定时器时间。
4 使用QProgressDialog类。这个Dialog是专门为了耗时长的操作定制的,它可以显示一个带有进度条和一个Cancel按钮的小对话框,在操作进行的同时显示进度,并且允许用户退出,具体API情参考 Class QProgressDialog.
在qt程序中,我们经常会遇到计算密集型操作或者存在大量I/O操作的时候,GUI就会发生冻结现象,并且会无法响应.仔细分析一下为什么会出现这种情况:因为GUI是一个主线程,而我们如果把计算密集型或者I/O操作放到主线程中去执行,(换句话说我们采用单一线程方案),那我们只能等待事件执行完之后GUI才能进行响应。
1 有种比较简单的办法是调用QApplication::processEvents(),但是属于治标不治本的方法。这个函数的作用主要就是处理qt在计算事件中处理某个点悬挂的事件。
qt文档中有句话影响比较深刻:In event you are running a local loop which calls this function continuously, without an event loop, the DeferredDelete events will not be processed.
2 从单一线程的方式改为多线程的方式。
qt应用程序中,多线程的操作实现是非常简单的:只需要子类化QThread,实现他的run()函数即可。但是多线程如果在单个CPU中运行相对单线程可能会慢点,多个CPU的话其优势会展现出来。下面我就实现一个多线程的简单案例:
//Thread.h
#ifndef THREAD_H
#define THREAD_H
#include <QThread>
#include<QDebug>
class Thread : public QThread
{
Q_OBJECT
public:
Thread(int _type);
~Thread();
void run();
private:
int type; //线程类型1或2
};
#endif // THREAD_H
//Thread.cpp
#include "Thread.h"
Thread::Thread(int _type)
:type(_type)
{
}
Thread::~Thread()
{
}
void Thread::run()
{
int count=5;
while(count>0)
{
qDebug()<<"Thread"<<type; //循环5次打印类型
count--;
}
}
//main.cpp main函数中调用
#include <QtCore/QCoreApplication>
#include "Thread.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Thread *pThread1=new Thread(1); //线程1
pThread1->start();
Thread *pThread2=new Thread(2); //线程2
pThread2->start();
return a.exec();
}
两次运行结果: