QT实现(2)
来源:互联网 发布:php 开发教育网站框架 编辑:程序博客网 时间:2024/05/18 00:18
首先看看connect函数的原型,这个函数在QObject类别当中定义:
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType =Qt::AutoConnection);
由于这个函数是static类型,所以在整个程序当中仅有一个函数,也正因为这样保证了函数的入口唯一性。不过这个函数的调用与这个函数的原型不太一样。
connect(sender, SIGNAL(clicked()), receiver, SLOT(close()));
# define SLOT(a) qFlagLocation("1"#a QLOCATION)# define SIGNAL(a) qFlagLocation("2"#a QLOCATION)
注意这两个宏前面的字符串1和2,这里实际是为了区分signal和slot。
const int flagged_locations_count = 2;static const char* flagged_locations[flagged_locations_count] = {0};const char *qFlagLocation(const char *method){ static int idx = 0; flagged_locations[idx] = method; idx = (idx+1) % flagged_locations_count; return method;}这里的idx每次累加1,正好将两个字符串放到不同的数组当中。而一个connect刚好同时存在一个signal和slot,这样的话每次connect调用之后都是的idx为0.完整的connect函数实现在qobject.cpp当中。在这个函数第一个调用是QInternal::activateCallbacks。
bool QInternal::activateCallbacks(Callback cb, void **parameters){ QInternal_CallBackTable *cbt = global_callback_table(); if (cbt && cb < cbt->callbacks.size()) { QList<qInternalCallback> callbacks = cbt->callbacks[cb]; bool ret = false; for (int i=0; i<callbacks.size(); ++i) ret |= (callbacks.at(i))(paratypedef bool (*qInternalCallback)(void **);
meters); return ret; } return false;}看起来这里首先调用一个函数,实际这个函数式利用宏定义出来的。struct QInternal_CallBackTable { QVector<QList<qInternalCallback> > callbacks;};Q_GLOBAL_STATIC(QInternal_CallBackTable, global_callback_table)#define Q_GLOBAL_STATIC(TYPE, NAME) \ static TYPE *NAME() \ { \ Q_GLOBAL_STATIC_INIT(TYPE, _StaticVar_); \ if (!this__StaticVar_.pointer && !this__StaticVar_.destroyed) { \ TYPE *x = new TYPE; \ if (!this__StaticVar_.pointer.testAndSetOrdered(0, x)) \ delete x; \ else \ static QGlobalStaticDeleter<TYPE > cleanup(this__StaticVar_); \ } \ return this__StaticVar_.pointer; \ }#define Q_GLOBAL_STATIC_INIT(TYPE, NAME) \ static QGlobalStatic<TYPE > this_ ## NAME \ = { Q_BASIC_ATOMIC_INITIALIZER(0), false }整个宏展开就是为了返回一个指针,由于最后的QGlobalStatic是一个全局的静态变量。所以这个宏并不是什么都没做,而是对这个全局指针进行检查,如果这个指针不存在,那么就将他给new出来,同时设置出师化值为0,如果初始化不成功,直接delete掉,反之为这个全局变量定义一个清理类别。因为析构函数和构造函数调用的顺序刚好相反,所以这里刚好先将指针给清理掉,然后再调用QGlobalStatic的析构函数。typedef bool (*qInternalCallback)(void **);这些回调函数在系统刚刚初始化的时候被设置。回调函数的原型如上面所示。到这里整个函数的流程很明了了,只不过借助了List和Vector的管理。整个函数在qglobal.cpp当中实现。回到connect函数,接下来是对参数进行检查,当参数有问题就打印调试错误。
static bool check_signal_macro(const QObject *sender, const char *signal, const char *func, const char *op){ int sigcode = extract_code(signal); if (sigcode != QSIGNAL_CODE) { if (sigcode == QSLOT_CODE) qWarning("Object::%s: Attempt to %s non-signal %s::%s", func, op, sender->metaObject()->className(), signal+1); else qWarning("Object::%s: Use the SIGNAL macro to %s %s::%s", func, op, sender->metaObject()->className(), signal); return false; } return true;}static int extract_code(const char *member){ return (((int)(*member) - '0') & 0x3);}首先减掉字符0的以得到数值,然后和0x03相与分理出数值1或者2;而这个正好是在宏里面添加的前缀标识符。函数里面的两个宏名称也不言而喻了,很明显,一个是数值1,另一个而是数值2.由于不能多个信号对应一个槽,所以这里要检测是否存在这种情况。
int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,const char *signal,bool normalizeStringData){ int i = indexOfMethodRelative<MethodSignal>(baseObject, signal, normalizeStringData); const QMetaObject *m = *baseObject; if (i >= 0 && m && m->d.superdata) { int conflict = m->d.superdata->indexOfMethod(signal); if (conflict >= 0) qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s", signal, m->d.superdata->d.stringdata, m->d.stringdata); } return i;}template<int MethodType>static inline int indexOfMethodRelative(const QMetaObject **baseObject, const char *method, bool normalizeStringData){ for (const QMetaObject *m = *baseObject; m; m = m->d.superdata) { int i = (MethodType == MethodSignal && priv(m->d.data)->revision >= 4) ? (priv(m->d.data)->signalCount - 1) : (priv(m->d.data)->methodCount - 1); const int end = (MethodType == MethodSlot && priv(m->d.data)->revision >= 4) ? (priv(m->d.data)->signalCount) : 0; if (!normalizeStringData) { for (; i >= end; --i) { const char *stringdata = m->d.stringdata + m->d.data[priv(m->d.data)->methodData + 5*i]; if (method[0] == stringdata[0] && strcmp(method + 1, stringdata + 1) == 0) { *baseObject = m; return i; } } } else if (priv(m->d.data)->revision < 5) { for (; i >= end; --i) { const char *stringdata = (m->d.stringdata + m->d.data[priv(m->d.data)->methodData + 5 * i]); const QByteArray normalizedSignature = QMetaObject::normalizedSignature(stringdata); if (normalizedSignature == method) { *baseObject = m; return i; } } } } return -1;}static inline const QMetaObjectPrivate *priv(const uint* data){ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
0 0
- QT实现(2)
- QT实现(3)
- QT实现(4)
- QT实现解析(1)
- 图像缩放实现(Qt)
- Qt实现天气预报与PM2.5监测系统(2)Qt运行环境
- 简单图形编程的学习(2)---点 (Qt实现)
- Qt 学习之路 2(18):事件--代码实现
- qt学习之个人画板的实现(2)
- QT实现简单的上位机软件(2)
- Qt实现金字塔图(3D和2D)
- QT画图教程4:QT实现2D画图
- 递归算法在QT中的实现(QT遍历文件夹)
- Qt Style Sheet的实现(Qt Designer Integration)
- 如何用Qt实现对Google API的应用(2)-- OAuth的各步骤实现
- Qt 实现桌面雪花飘落 - 修改2
- 用Qt实现2D绘图
- 转:QT实现阴影窗口(一)
- Error creating bean with name 'sessionFactory' defined in class path resource [beans.xml]: Invocatio
- 并查集(持续更新)
- 记忆摘要
- inotify -- Linux 2.6 内核中的文件系统变化通知机制
- 求逆序数
- QT实现(2)
- POJ 3461 Oulipo
- SAS DM数据准备读书笔记8(探索性数据分析)
- 异常javax.servlet.jsp.JspException cannot be resolved
- 【最小生成树 kruskal】 hdu 1102 Constructing Roads
- 设计模式 --- 1 :动态代理 初识动态代理
- USACO Palindromic Squares
- Session Cookies Cache 的区别
- 每隔一段时间自动运行程序dos命令 schtasks (转)