上回说到,柯南君展示了Qt无耻的一面后,众道友心灰意冷。修仙的修仙,搞基的搞基。原本热闹的Qt道场,一下子冷清了下来。只剩哥一个人坐在联想大厦的塑像前作冥想状,“世界如果失去了Qt会怎样“?会变成知书识仪,天下大同的理想世界吗?中国五千年的24部血泪史昭示了”This is just a dream“。一个无耻倒下了,一个更无耻的又站起来。这时大屏幕上的图片映入贫道的眼帘,
霎那间贫道的内心被震撼了,终于领悟了修仙的真谛,那就是“誓将揭露Qt无耻的事业进行到底”。此时的哥又斗志昂扬,走在了修仙的大道上。
各位道友请看此例,
void NotifyOtherThread(DWORD dwOtherThreadID) { CString str = "i am here"; ::PostThreadMessage(dwOtherThreadID, WS_NOTIFY, &str, NULL); }
我们知道在Windows的世界里,用Post跨线程发送消息是异步的,如果按照上面的实例,把local 类(结构)变量作为参数发送,那么接受方得到的参数内容会是混乱的,从而引起程序的崩溃。因为他一出函数体就被释放掉了。所以,我们从小就被告知,local类变量不能作为Post的参数。
那么在Qt中还是这样吗?
class MyTestA : public QObject { Q_OBJECT public: void emitSignal() { signalMyTestA("I am here."); } public slots: void slotMyTestA() { qDebug()<<"slotMyTestA is called."; } signals: void signalMyTestA(QString str); }; class MyTestB : public QObject { Q_OBJECT public slots: void slotMyTestB(QString str) { qDebug()<<"string is "<<str; } signals: void signalMyTestB(); }; extern MyTestB *g_pMyTestB; extern MyTestA *g_pMyTestA; class MyTestC : public QThread { Q_OBJECT public: MyTestC():QThread(NULL) { } void run() { MyTestA a; QObject::connect(&a,SIGNAL(signalMyTestA(QString)),g_pMyTestB,SLOT(slotMyTestB(QString))); a.emitSignal(); exec(); } public slots: void slotMyTestC() { qDebug()<<"slotMyTestC is called."; } signals: void signalMyTestC(); }; /////////////////////// MyTestB *g_pMyTestB = NULL; MyTestA *g_pMyTestA = NULL; int main(int argc, char *argv[]) { QApplication app(argc, argv); MyTestB b; g_pMyTestB = &b; MyTestC c; c.start(); return app.exec(); }
只见输出窗口打出了:string is "I am here." 居然没有发生对象混乱,程序安然无恙,Local QString参数完美地被发送到了另外的线程。众道友的失落的心又重新热了起来,内心对Qt又充满了无限的期望。但俗话说得好,一朝被蛇咬,十年怕井绳。一些细心的道友,又把QString换成了QByteArray,QDate,QPixmap等常用的Qt类,无一错乱。十分,十分,只见铺天盖地的写有十的积分牌举了起来。此时语言已经是多余的了。终于不用再为Local变量烦恼了,跨线程不能使用Local变量这一无耻的行规终于被扫入了历史的垃圾箱。从此Coder道友们站起来了........。在一片赞扬声中,贫道则陷入了深深的思索中,事有反常即为妖。
突然思绪一闪,柯南君的音容相貌又浮现在了眼前。此时贫道把代码稍微改写了下
struct sOwn { QString m_str; }; class MyTestA : public QObject { Q_OBJECT public: void emitSignal() { sOwn s; s.m_str = "i am here"; signalMyTestA(s); } public slots: void slotMyTestA() { qDebug()<<"slotMyTestA is called."; } signals: void signalMyTestA(sOwn sItem); }; class MyTestB : public QObject { Q_OBJECT public slots: void slotMyTestB(sOwn sItem) { qDebug()<<"string is "<<sItem.m_str; } signals: void signalMyTestB(); }; extern MyTestB *g_pMyTestB; extern MyTestA *g_pMyTestA; class MyTestC : public QThread { Q_OBJECT public: MyTestC():QThread(NULL) { } void run() { MyTestA a; QObject::connect(&a,SIGNAL(signalMyTestA(sOwn)),g_pMyTestB,SLOT(slotMyTestB(sOwn))); a.emitSignal(); exec(); } public slots: void slotMyTestC() { qDebug()<<"slotMyTestC is called."; } signals: void signalMyTestC(); }; ///////////////////////////////// MyTestB *g_pMyTestB = NULL; MyTestA *g_pMyTestA = NULL; int main(int argc, char *argv[]) { QApplication app(argc, argv); MyTestB b; g_pMyTestB = &b; MyTestC c; c.start(); return app.exec(); }
一道闪电从空中划过,当代码执行到"QObject::connect(&a,SIGNAL(signalMyTestA(sOwn)),g_pMyTestB,SLOT(slotMyTestB(sOwn)));"这一句时,”QObject::connect: Cannot queue arguments of type 'sOwn' “刺眼地跳了出来。这句话通俗地说就是,你被发好人卡了,你被拒签了..., 总之就是因为你的对象不是Q家人,你就进不了Q家门,自然就connect不了slot。
这一刻Qt你又赢了,你又一次玩弄了众道友的感情,你继承了中国足球的光荣的传统。各届国家队在这一刻灵魂附体!在这一刻你不是一个人在战斗!你就像中国足球那样,在人绝望的时候给人希望,在希望的时候给人以绝望。
此时众道友仰天长叹,大声质问道,Qt你来自希望国,秉承着“All object is created equal”的信念(Qt内牛满面,哥本挪威人,奈何成花旗),却行歧视之勾当,意欲何为?更有欲到花旗传道的道友,挥舞着印有No Pass的护照,叹道,“人被拒签,难道自己写的程序也要被拒签,朗朗乾坤,公理何在,天理何存”。说完就要自碎金丹,化作散仙,不再为这个充满着无耻之徒的尘世所困扰。就在这时,一道红光飞过,仔细一看是一条鲜红的红领巾,上面写着几个屎黄色的希望文:
"qRegisterMetaType"
落款人:红领巾。
贫道急忙把此函数放到代码中,
struct sOwn { QString m_str; }; class MyTestA : public QObject { Q_OBJECT public: void emitSignal() { sOwn s; s.m_str = "i am here"; signalMyTestA(s); } public slots: void slotMyTestA() { qDebug()<<"slotMyTestA is called."; } signals: void signalMyTestA(sOwn sItem); }; class MyTestB : public QObject { Q_OBJECT public slots: void slotMyTestB(sOwn sItem) { qDebug()<<"string is "<<sItem.m_str; } signals: void signalMyTestB(); }; extern MyTestB *g_pMyTestB; extern MyTestA *g_pMyTestA; class MyTestC : public QThread { Q_OBJECT public: MyTestC():QThread(NULL) { } void run() { MyTestA a; qRegisterMetaType<sOwn>("sOwn"); QObject::connect(&a,SIGNAL(signalMyTestA(sOwn)),g_pMyTestB,SLOT(slotMyTestB(sOwn))); a.emitSignal(); exec(); } public slots: void slotMyTestC() { qDebug()<<"slotMyTestC is called."; } signals: void signalMyTestC(); }; ///////////////////// MyTestB *g_pMyTestB = NULL; MyTestA *g_pMyTestA = NULL; int main(int argc, char *argv[]) { QApplication app(argc, argv); MyTestB b; g_pMyTestB = &b; MyTestC c; c.start(); return app.exec(); }
string is "I am here." 重回大地,众人又开始捻胡微笑,皆叹Qt的人性化。不用收入证明,不用公司邀请信,不用签证面试,只要你用了qRegisterMetaType,你就是Q家人了。
所以,当signal异步调用slot时,如果你的对象不是Qt所支持的,就需要调用qRegisterMetaType,而后就可以将Local class变量放到signal中,安全地传递给slot。
一切就是这么简单。Ye!!!,众道友做了个00后的标准动作,以表达自己的欢乐之情。
但是快乐的时光总是短暂的,又一幕悲剧拉开了序幕。
话说C++三朝元老,int。最近痴迷欧美音乐,给自己取了个鼎鼎响亮的艺名"雷帝嘎嘎"(LADYGAGA)。结果,
typedef int LADYGAGA; struct sOwn { QString m_str; }; class MyTestA : public QObject { Q_OBJECT public: void emitSignal() { int i = 9; signalMyTestA(i); } public slots: void slotMyTestA() { qDebug()<<"slotMyTestA is called."; } signals: void signalMyTestA(LADYGAGA lg); }; class MyTestB : public QObject { Q_OBJECT public slots: void slotMyTestB(LADYGAGA lg) { qDebug()<<"string is "<<lg; } signals: void signalMyTestB(); }; extern MyTestB *g_pMyTestB; extern MyTestA *g_pMyTestA; class MyTestC : public QThread { Q_OBJECT public: MyTestC():QThread(NULL) { } void run() { MyTestA a; QObject::connect(&a,SIGNAL(signalMyTestA(LADYGAGA)),g_pMyTestB,SLOT(slotMyTestB(LADYGAGA))); a.emitSignal(); exec(); } public slots: void slotMyTestC() { qDebug()<<"slotMyTestC is called."; } signals: void signalMyTestC(); }; ////////////////////////////// MyTestB *g_pMyTestB = NULL; MyTestA *g_pMyTestA = NULL; int main(int argc, char *argv[]) { QApplication app(argc, argv); MyTestB b; g_pMyTestB = &b; MyTestC c; c.start(); return app.exec(); }
本年度最具爆炸性新闻诞生了“QObject::connect: Cannot queue arguments of type 'LADYGAGA',(Make sure 'LADYGAGA' is registered using qRegisterMetaType().)” 。世界震惊了,大家宁可相信“发改委宣布降低油价”,也不愿相信,编程界基本数据类型的三朝元老,久经考验的C++主义战士,int同志居然因为使用众人皆知的艺名connect slot,被拒签了。三大社(美联社,法新社,路透社)联合发文<<悲剧,三朝元老使用艺名,被拒签>>。2月30号X民日报头版发表评论员文章《老同志,倚老卖老要不得》。
从上诉评论中我们不难看出"当signal和slots是异步时,哪怕数据类型用qRegisterMetaTyoe注册过,甚至是基本数据类型,connect用的参数类型不是注册名,而是typedef或者define的别名,connect也会失败,如果要使用别名,也需要对别名进行重新注册。Qt只认名,不认人"。对于上面的例子,如果要使connect能正常使用,需调用qRegisterMetaType<LADYGAGA>("LADYGAGA");,虽然LADYGAGA其实就是int。
Qt总是在意想不到的时间,意想不到的地点,展示其无耻的一面。
太史公曾曰,世上无耻者,皆不过Qt也。
古人不曾欺我。
而众道友此时却没有因为Qt的再次无耻,而愤愤不平,反而露出一丝猥琐的笑容,心里不禁乐道,老东西,你也有今天。
而贫道又陷入了沉思,Qt你的底线到底在哪里?
欲知后事如何,请看下回分解。