转载自:http://www.cnblogs.com/andreitang/archive/2011/08/08/2128505.html 谢谢无私的分享
第二回 拒签,不只天朝有
上回说到,柯南君展示了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中还是这样吗?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
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道友们站起来了........。在一片赞扬声中,贫道则陷入了深深的思索中,事有反常即为妖。
突然思绪一闪,柯南君的音容相貌又浮现在了眼前。此时贫道把代码稍微改写了下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
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"
落款人:红领巾。
贫道急忙把此函数放到代码中,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
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)。结果,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
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你的底线到底在哪里?