我们都知道信号槽.
但很多同学不知道怎么用它在Qt里实现类与类通信.
首先要搞清楚,Qt类与类之间通信有2种情况:
(1) 两个类之间没有父子关系;
(2) 两个类之间有父子关系;
这篇文章讲的是有父子关系的2个类使用信号槽通信.
当然,没有父子关系的也能用信号槽通信,但是必须要有一个设计成单例模式.
Qt单例模式
假设有2个类: Father和Son.
它们有父子关系,其中Father包含了Son.
那么Father如何发送数据给Son或者Son如何发送数据给Father呢?
1 Father发送数据给Son父发给子这个很简单,就算不使用信号槽也可以实现.
例如Father想发"helloworld"给Son,就可以:
(1) 在Son里定义一个函数setData(QString data);
(2) Father里调用son->setDate("helloworld");即可;
.h如下:
class Son {public: explicit Son(); void setData(QString data);private: QString buf;};class Father {public: explicit Father(); Son *s;};
.cpp如下:
Son::Son(){}void Son::setData(QString data){ buf = data; qDebug() << buf;}Father::Father(){ s = new Son(); s->setData("helloworld");}
输出结果:
我们可以看大,Father里的helloworld确实设到了Son里.
使用信号槽传的方法如下:
(1) 在父类里定义一个信号void signDataOk(QString data);
(2) 在子类写一个槽函数: void slotGetData(QString d);
(3) 注意信号和槽函数形参必须一模一样;
(4) 在父类里关联信号槽.当信号发出时就会触发子类槽函数,在子类槽函数的形参中即可获取数据.
.h代码:
//因为使用到信号槽,所以必须继承QObject和在类里定义Q_OBJECT宏class Son : public QObject { Q_OBJECTpublic: explicit Son(); void setData(QString data);private: QString buf;private slots: void slotGetData(QString d);};class Father : public QObject{ Q_OBJECTpublic: explicit Father(); Son *s;signals: void signDataOk(QString data);};
.cpp代码:
Son::Son(){}void Son::slotGetData(QString d){ qDebug() << "recv=" + d;}void Son::setData(QString data){ buf = data; qDebug() << buf;}Father::Father(){ s = new Son(); //手动关联信号槽 connect(this, SIGNAL(signDataOk(QString)), s, SLOT(slotGetData(QString))); //发射信号,会触发Son的槽函数 emit signDataOk("hello world");}
2 Son发数据给Father
Father发送数据给Son其实很简单,因为在Father里可以轻松的获取到Son的对象指针.
但是反过来就不行了,因为在Son里很难获取到Father的指针,而且Qt官方也不推荐这样做,因为"子对象获取父对象的指针会很危险".
那么这个时候Son想发数据给Father必须得使用信号槽了.
其实方法和之前说的差不多,也是定义信号,然后关联信号槽.
由于非常像,直接放代码了:
.h文件:
//因为使用到信号槽,所以必须继承QObject和在类里定义Q_OBJECT宏class Son : public QObject { Q_OBJECTpublic: explicit Son();private: QString buf; QTimer *timer;signals: void signDataOk(QString data);private slots: void slotTimeOut();};class Father : public QObject{ Q_OBJECTpublic: explicit Father(); Son *s;private slots: void slotGetData(QString d);};
.cpp文件:
Son::Son(){ timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(slotTimeOut())); timer->start(1000); //每隔一秒发送一次}void Son::slotTimeOut(){ //发射信号,会触发Son的槽函数 emit signDataOk(QString("hello world"));}Father::Father(){ s = new Son(); //手动关联信号槽 connect(s, SIGNAL(signDataOk(QString)), this, SLOT(slotGetData(QString)));}void Father::slotGetData(QString d){ qDebug() << "recv=" + d;}
运行结果:
后记
子通过信号槽发送数据给父对象这种框架是很常见的.
例如摄像头监控界面.
我们知道主界面里是不能死循环的,在主界面里死循环直接界面卡死,不信你试试.
所以必须要用子线程来循环接收图像,然后通过信号发送给主界面显示.
这种框架的共同点:
父界面显示数据,子线程死循环接收数据发送给父界面.
做Qt项目,假如功能包括串口,CAN,485通信等等,都可以使用这种框架来设计.
☆ END ☆关注梅老师
学习嵌入式
梅老师