www.myuml.net

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  5 随笔 :: 0 文章 :: 14 评论 :: 0 Trackbacks

查看Qt4的一些示例项目的时候,使用设计器打开其UI文件,在文件中竟然找不到signal和slot的连接。但是最终的程序,slot却又能准确的响应信号。打开通过ui文件自动生成的c++文件,其中也找不到connect语句,到底是怎么一回事?

经过逐语句的分析。终于发现连接的原因就在于setUi函数的最后一句

QMetaObject::connectSlotsByName(MainWindow);

找到该静态函数

void QMetaObject::connectSlotsByName(QObject *o)
{
    if (!o)
        return;
    const QMetaObject *mo = o->metaObject();
    Q_ASSERT(mo);
    const QObjectList list = qFindChildren<QObject *>(o, QString());
    for (int i = 0; i < mo->methodCount(); ++i) {

/*

slot是方法的名字,在以下的内容中,会把它分成三部分(依次判断该方法是否满足这三部分的条件):

第一部分:on_

第二部分:子对象名

第三部分:信号名

*/
        const char *slot = mo->method(i).signature();
        Q_ASSERT(slot);

//以下一行用来判断slot的前三位是否是on_,如果不是,就跳过这个方法。
        if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
            continue;
        bool foundIt = false;

//遍历子对象。
        for(int j = 0; j < list.count(); ++j) {
            const QObject *co = list.at(j);

//得到子对象名。
            QByteArray objName = co->objectName().toAscii();
            int len = objName.length();

//要求slot跳过前3位(on_)后,接下来的子字符串和子对象名相同,并且接着该子字符串又是一个_

//如果达不到这个要求,continue
            if (!len || qstrncmp(slot + 3, objName.data(), len) || slot[len+3] != '_')
                continue;
            const QMetaObject *smo = co->metaObject();
            int sigIndex = smo->indexOfMethod(slot + len + 4);
            if (sigIndex < 0) { // search for compatible signals
                int slotlen = qstrlen(slot + len + 4) - 1;

//搜索该子对象所能引发的信号
                for (int k = 0; k < co->metaObject()->methodCount(); ++k) {
//方法类型如果符合要求

                    if (smo->method(k).methodType() != QMetaMethod::Signal)
                        continue;

//如果slot最后的子字符串和信号名相同

                    if (!qstrncmp(smo->method(k).signature(), slot + len + 4, slotlen)) {
                        sigIndex = k;
                        break;
                    }
                }
            }
            if (sigIndex < 0)
                continue;

//连接操作
            if (QMetaObject::connect(co, sigIndex, o, i)) {
                foundIt = true;
                break;
            }
        }

//连接成功
        if (foundIt) {
            // we found our slot, now skip all overloads
            while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
                  ++i;
        }

//连接失败

else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
            qWarning("QMetaObject::connectSlotsByName: No matching signal for %s", slot);
        }
    }
}

得出此结论:自动生成的文件中,该函数总会存在setUi函数的最后一句。

该函数的作用就是寻找setUi的唯一指针参数MainWindow所指向对象的成员函数,

该成员函数的名字如果满足以下条件,就做连接操作。

函数名规则:on_子对象名_信号名

函数签名(即返回值与参数要符合slot要求)

所以,我们可以这样做:在qt设计器中添加按纽或者菜单项或者按纽项后,不用在设计器中手动做连接操作。

我们只要在主窗口类中添加符合条件的成员函数即可。

函数名规则:on_子对象名_信号名

函数签名(即返回值与参数要符合slot要求)

例如:

在设计器中添加一个菜单项,其对应的action为actionNew

那么在主窗口类中添加以下的函数

public slots:

       void on_actionNew_triggered();

当切换这个菜单时,会自动执行上面的成员函数。

posted on 2009-10-26 13:11 寻舟 阅读(2199) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理