写这篇的时候感觉有点像写之前Android主线程与子线程间的通信消息队列,其实需要这么做的原因基本相同,即QT在主线程(UI线程)中某些阻塞行为会造成UI的更新的阻塞,举例来说,在UI线程中创建一个while循环,并在这个while循环中对UI进行更新,运行结果是UI完全无响应,因为UI线程一直卡在while中无法跳出来去完成更新,虽然它不断的得到了更新UI的通知。
因此在本篇中我们将通过多线程的方式来解决此类问题。
QT中已经替我们实现了一个线程类QThread,我们只需要继承它就好。使用时只需->start()即可。
1 2 3 4 5 6 7 8 9 10 | class MyThread : public QThread { Q_OBJECT public: MyThread(); signals://定义一个信号 void sendString(QString); protected: void run(); }; |
上面的代码简单实现了一个线程类的头文件,这里注意一下定义的signals(信号)。
信号与槽是QT特有的一个通信机制,简单阐述一下其运用在线程间的工作流程。
首先我们在子线程的头文件中定义一个信号,例如 void sendString(QString),这个信号函数不需要在cpp中实现,因为它会被绑定到某一个槽函数上,我们只需要实现那个槽函数就等于实现了这个信号函数。
接下来我们在UI线程中定义一个槽函数,头文件代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void printMsg(Qstring str);//定义一个槽函数 private: Ui::MainWindow *ui; }; |
并在MainWindow.cpp里实现它
1 2 3 4 5 | void MainWindow::printMsg(Qstring str){ //这里添加代码对str进行操作 } |
接下来是这个信号和槽的使用方法,首先需要使用connect方法将子线程中的信号函数与UI线程中的槽函数绑定在一起。
1 | QObeject::connect( obj1, SIGNAL( mySignal() ), obj2, SLOT( mySlot() ) ); |
obj1在本例中为子线程对象即MyThread,obj2为UI对象即MainWindow
这个方法通常在构造函数初始化时即可调用,也可以在任意地方进行设定,只要能成功传如对象即可。
至此信号与槽成功的对接上了,如果为对接上,在程序运行的输出窗口会进行提示,no found such…
当我们需要在其他线程中改变UI线程的某个UI时,在其他线程中使用以下方式发送信号
1 | emit sendString(QString("这里输入要打印的字符")); |
此时QT会自动寻找与信号sendString相匹配的槽函,并执行该槽函数,对我们传入的对象进行处理,比如在某个text框里打印这句话。
在多线程中使用信号与槽进行数据交互可以有效的避免线程安全问题(UI线程不是线程安全的)。
关于信号与槽的应用还有很多,有机会再慢慢道来。
本文到此,谢谢关注。
BeiTown
2013.05.01