Qt那点事儿(二)

第二回 拒签,不只天朝有

上回说到,柯南君展示了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你的底线到底在哪里?

欲知后事如何,请看下回分解。




posted on 2011-08-08 09:40  樱桃小锤子  阅读(4222)  评论(9编辑  收藏  举报