信号和槽是Qt应用开发的基础,它可是将两个毫无关系的对象连接在一起,槽和普通的C++函数是一样的,只是当它和信号连接在一起后,当发送信号的时候,槽会自动被调用只有加入了Q_OBJECT,你才能使用QT中的signal和slot机制。
所有QObject的派生类在官方文档中都推荐在头文件中放置宏Q_OBJECT,那么该宏到底为我们做了哪些工作?在qobjectdef.h中有下面的代码:
view plain
#define Q_OBJECT \
public: \
Q_OBJECT_CHECK \
static const QMetaObject staticMetaObject; \
Q_OBJECT_GETSTATICMETAOBJECT \
virtual const QMetaObject *metaObject() const; \
virtual void *qt_metacast(const char *); \
QT_TR_FUNCTIONS \
virtual int qt_metacall(QMetaObject::Call, int, void **); \
private:
首先定义了一个Q_OBJECT_CHECK宏,这个宏在Q_OBJECT宏的上方定义:
view plain
#define Q_OBJECT_CHECK \
template inline void qt_check_for_QOBJECT_macro(const T &_q_argument) const \
{ int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument); i = i; }
Q_OBJECT_CHECK实现了一个模板函数,该函数调用了qYouForgotTheQ_OBJECT_Macro的函数,qYouForgotTheQ_OBJECT_Macro在宏Q_OBJECT_CHECK下面有定义:
view plain
template
inline int qYouForgotTheQ_OBJECT_Macro(T, T) { return 0; }
template
inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {}
从返回值情况上可以看到,调用的是有int返回值的那个模板函数。但是很不明白,为什么之后还要添加一句 i=i?,刨根之后,发现Q_OBJECT_CHECK宏并没有做什么工作。
然后Q_OBJECT又帮我们定义了一个静态的元对象,
view plain
static const QMetaObject staticMetaObject; \
Q_OBJECT_GETSTATICMETAOBJECT \
Q_OBJECT_GETSTATICMETAOBJECT宏从名字上看就是为了获取这个元对象,确实在定义了Q_NO_DATA_RELOCATION宏的情况下,Q_OBJECT_GETSTATICMETAOBJECT宏就为我们定义了获取静态元对象的方法。
view plain
#ifdef Q_NO_DATA_RELOCATION
#define Q_OBJECT_GETSTATICMETAOBJECT static const QMetaObject &getStaticMetaObject();
#else
#define Q_OBJECT_GETSTATICMETAOBJECT
#endif
之后Q_OBJECT宏又给我们定义了连个虚函数用来获取元对象指针和设置源对象。
view plain
virtual const QMetaObject *metaObject() const; \
virtual void *qt_metacast(const char *); \
而定义的 QT_TR_FUNCTIONS 则表示是否支持I18N。
view plain
#ifndef QT_NO_TRANSLATION
# ifndef QT_NO_TEXTCODEC
// full set of tr functions
// ### Qt 5: merge overloads
# define QT_TR_FUNCTIONS \
static inline QString tr(const char *s, const char *c = 0) \
{ return staticMetaObject.tr(s, c); } \
static inline QString trUtf8(const char *s, const char *c = 0) \
{ return staticMetaObject.trUtf8(s, c); } \
static inline QString tr(const char *s, const char *c, int n) \
{ return staticMetaObject.tr(s, c, n); } \
static inline QString trUtf8(const char *s, const char *c, int n) \
{ return staticMetaObject.trUtf8(s, c, n); }
# else
// no QTextCodec, no utf8
// ### Qt 5: merge overloads
# define QT_TR_FUNCTIONS \
static inline QString tr(const char *s, const char *c = 0) \
{ return staticMetaObject.tr(s, c); } \
static inline QString tr(const char *s, const char *c, int n) \
{ return staticMetaObject.tr(s, c, n); }
# endif
#else
// inherit the ones from QObject
# define QT_TR_FUNCTIONS
#endif
只要有所实现,tr的方法就通过静态对象staticMetaObject的tr方法来实现。最后Q_OBJECT又定义了一个虚函数
view plain
virtual int qt_metacall(QMetaObject::Call, int, void **);
看名字定义,应该是用来对元对象的调用。
合起来看所有的Q_OBJECT定义,都是为了操作元对象,并没有所谓的信号和槽,属性等内容,很显然,QObject对象能够支持这些功能,必然是通过QMetaObject这个元对象来实现的。尽管QMetaObject对象的实现有些庞大,但这个是所有的QOBject中最核心的一个实现,因此需要仔细分析该对象的每个定义:
view plain
struct Q_CORE_EXPORT QMetaObject
{
const char *className() const; // 类名
const QMetaObject *superClass() const; // 父类的元对象
QObject *cast(QObject *obj) const; // 强制一个对象
#ifndef QT_NO_TRANSLATION
// ### Qt 4: Merge overloads
QString tr(const char *s, const char *c) const; // 翻译函数
QString trUtf8(const char *s, const char *c) const;
QString tr(const char *s, const char *c, int n) const;
QString trUtf8(const char *s, const char *c, int n) const;
#endif // QT_NO_TRANSLATION
int methodOffset() const; // 方法偏移量
int enumeratorOffset() const; // 枚举偏移量
int propertyOffset() const; // 属性偏移量
int classInfoOffset() const; // 类信息数目
int constructorCount() const; // 构造函数数目
int methodCount() const; // 方法数目
int enumeratorCount() const; // 枚举数据
int propertyCount() const; // 属性数目
int classInfoCount() const; // 类信息数目
int indexOfConstructor(const char *constructor) const; // 构函函数索引
int indexOfMethod(const char *method) const; // 方法索引
int indexOfSignal(const char *signal) const; // 信号量索引
int indexOfSlot(const char *slot) const; // 槽索引
int indexOfEnumerator(const char *name) const; // 枚举索引
int indexOfProperty(const char *name) const; // 属性索引
int indexOfClassInfo(const char *name) const; // 类信息索引
QMetaMethod constructor(int index) const; // 构造方法
QMetaMethod method(int index) const; // 方法
QMetaEnum enumerator(int index) const; // 枚举
QMetaProperty property(int index) const; // 属性
QMetaClassInfo classInfo(int index) const; // 类属性信息
QMetaProperty userProperty() const; // 用户属性
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
static bool checkConnectArgs(const char *signal, const char *method);
static QByteArray normalizedSignature(const char *method);
static QByteArray normalizedType(const char *type);
// internal index-based connect
static bool connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index,
int type = 0, int *types = 0);
// internal index-based disconnect
static bool disconnect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index);
static bool disconnectOne(const QObject *sender, int signal_index,
const QObject *receiver, int method_index);
// internal slot-name based connect
static void connectSlotsByName(QObject *o);
// internal index-based signal activation
static void activate(QObject *sender, int signal_index, void **argv); //obsolete
static void activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv); //obsolete
static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv);
static void activate(QObject *sender, const QMetaObject *, int from_local_signal_index, int to_local_signal_index, void **argv); //obsolete
// internal guarded pointers
static void addGuard(QObject **ptr);
static void removeGuard(QObject **ptr);
static void changeGuard(QObject **ptr, QObject *o);
static bool invokeMethod(QObject *obj, const char *member,
Qt::ConnectionType,
QGenericReturnArgument ret,
QGenericArgument val0 = QGenericArgument(0),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument());
static inline bool invokeMethod(QObject *obj, const char *member,
QGenericReturnArgument ret,
QGenericArgument val0 = QGenericArgument(0),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument())
{
return invokeMethod(obj, member, Qt::AutoConnection, ret, val0, val1, val2, val3,
val4, val5, val6, val7, val8, val9);
}
static inline bool invokeMethod(QObject *obj, const char *member,
Qt::ConnectionType type,
QGenericArgument val0 = QGenericArgument(0),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument())
{
return invokeMethod(obj, member, type, QGenericReturnArgument(), val0, val1, val2,
val3, val4, val5, val6, val7, val8, val9);
}
static inline bool invokeMethod(QObject *obj, const char *member,
QGenericArgument val0 = QGenericArgument(0),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument())
{
return invokeMethod(obj, member, Qt::AutoConnection, QGenericReturnArgument(), val0,
val1, val2, val3, val4, val5, val6, val7, val8, val9);
}
QObject *newInstance(QGenericArgument val0 = QGenericArgument(0),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument()) const;
enum Call {
InvokeMetaMethod,
ReadProperty,
WriteProperty,
ResetProperty,
QueryPropertyDesignable,
QueryPropertyScriptable,
QueryPropertyStored,
QueryPropertyEditable,
QueryPropertyUser,
CreateInstance
};
int static_metacall(Call, int, void **) const;
static int metacall(QObject *, Call, int, void **);
#ifdef QT3_SUPPORT
QT3_SUPPORT const char *superClassName() const;
#endif
struct { // private data
const QMetaObject *superdata; // 父类
const char *stringdata; // 类名
const uint *data; // 任意指向数据的指针
const void *extradata; // 扩展数据
} d;
};
QMetaObject就内部一个结构体对象,包含了四个部分,分别是父类对象,自己元对象的名称,以及一个指针任意值的指针数据和扩展数据,一般情况下,d.data表示的是QMetaObjectPrivate对象指针,在priv函数中可以找到一些痕迹:
view plain
static inline const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast(data); }
按照Qt的实现惯例,使用Private对象做一些具体的工作,于是就有了QMetaObjectPrivate和QObjectPrivate
view plain
struct QMetaObjectPrivate // 注意是一个结构体
{
int revision; // 版本
int className; // 类名,注意类型
int classInfoCount, classInfoData; // 类信息数据和数量
int methodCount, methodData; // 方法数据和数量
int propertyCount, propertyData; // 属性数据和数量
int enumeratorCount, enumeratorData; // 枚举数据和数量
int constructorCount, constructorData; //since revision 2 // 构造函数数据和数量
int flags; //since revision 3 // 标记
int signalCount; //since revision 4 // 信号量数目
// revision 5 introduces changes in normalized signatures, no new members
// 从元数据中获取QMetaObjectPrivate对象指针,从data中得到!!
static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
{ return reinterpret_cast(metaobject->d.data); }
static int indexOfSignalRelative(const QMetaObject **baseObject,
const char* name,
bool normalizeStringData);
static int indexOfSlot(const QMetaObject *m,
const char *slot,
bool normalizeStringData);
static int originalClone(const QMetaObject *obj, int local_method_index);
#ifndef QT_NO_QOBJECT
//defined in qobject.cpp
enum DisconnectType { DisconnectAll, DisconnectOne };
static bool connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index,
int type = 0, int *types = 0);
static bool disconnect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index,
DisconnectType = DisconnectAll);
static inline bool disconnectHelper(QObjectPrivate::Connection *c,
const QObject *receiver, int method_index,
QMutex *senderMutex, DisconnectType);
#endif
};
==================================================================
view plain
class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
Q_DECLARE_PUBLIC(QObject)
public:
struct ExtraData // 定义额外数据
{
ExtraData() {}
#ifndef QT_NO_USERDATA
QVector userData;
#endif
QList propertyNames; // 属性名列表
QList propertyValues; // 属性值
};
struct Connection // 定义连接信息
{
QObject *sender; // 发送者
QObject *receiver; // 接受者
int method; // 方法
uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
QBasicAtomicPointer argumentTypes; // 参数类型
// The next pointer for the singly-linked ConnectionList
Connection *nextConnectionList; // 下一个连接对象列表
//senders linked list
Connection *next; // 下一个连接
Connection **prev; // 上一个连接
~Connection();
};
// ConnectionList is a singly-linked list
struct ConnectionList { // 定义连接列表
ConnectionList() : first(0), last(0) {}
Connection *first; // 连接首
Connection *last; // 连接尾
};
struct Sender // 定义发送者
{
QObject *sender; // 发送者
int signal; // 信号
int ref; // 引用计数
};
QObjectPrivate(int version = QObjectPrivateVersion);
virtual ~QObjectPrivate();
void deleteChildren(); // 删除所有子节点
void setParent_helper(QObject *); // 设置父节点
void moveToThread_helper(); // 转到某个线程中
void setThreadData_helper(QThreadData *currentData, QThreadData *targetData); // 设置线程数据
void _q_reregisterTimers(void *pointer); // 设置注册时间
bool isSender(const QObject *receiver, const char *signal) const; // 判断信号量是否为发送者
QObjectList receiverList(const char *signal) const; // 接受信号的对象列表
QObjectList senderList() const; // 发出信息列表
void addConnection(int signal, Connection *c); // 添加一个信号连接
void cleanConnectionLists(); // 清理连接列表
#ifdef QT3_SUPPORT
void sendPendingChildInsertedEvents();
void removePendingChildInsertedEvents(QObject *child);
#endif
static inline Sender *setCurrentSender(QObject *receiver,
Sender *sender); // 设置当前发送者
static inline void resetCurrentSender(QObject *receiver,
Sender *currentSender,
Sender *previousSender); // 重置当前发送者
static int *setDeleteWatch(QObjectPrivate *d, int *newWatch); // 设置删除监听
static void resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch); // 重置删除监听
static void clearGuards(QObject *); // 清除管理者
static QObjectPrivate *get(QObject *o) { // 从QObject对象中获取QObjectPrivate
return o->d_func();
}
int signalIndex(const char *signalName) const; // 信号索引
inline bool isSignalConnected(uint signalIdx) const; // 判断是否为信号连接
public:
QString objectName; // 对象名字
ExtraData *extraData; // extra data set by the user // 额外数据
QThreadData *threadData; // id of the thread that owns the object // 线程数据
QObjectConnectionListVector *connectionLists; // 连接列表数组
Connection *senders; // linked list of connections connected to this object // 发送者连接
Sender *currentSender; // object currently activating the object // 当前发送者
mutable quint32 connectedSignals[2]; // 连接信号
#ifdef QT3_SUPPORT
QList pendingChildInsertedEvents;
#else
// preserve binary compatibility with code compiled without Qt 3 support
// keeping the binary layout stable helps the Qt Creator debugger
void *unused; // 保留
#endif
QList > eventFilters;
union {
QObject *currentChildBeingDeleted; // 当前子节点被删除
QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
};
// these objects are all used to indicate that a QObject was deleted
// plus QPointer, which keeps a separate list
QAtomicPointer sharedRefcount; // 共享引用计数
int *deleteWatch; // 删除监听者
};
QObjectPrivate从QObjectData派生下来:
view plain
class
#if defined(__INTEL_COMPILER) && defined(Q_OS_WIN)
Q_CORE_EXPORT
#endif
QObjectData {
public:
virtual ~QObjectData() = 0;
QObject *q_ptr; // 当前指向的QOBject
QObject *parent; // 指向的QObject父类
QObjectList children; // 孩儿们
uint isWidget : 1; // 是否为widget的标记
uint pendTimer : 1; // 开启时钟
uint blockSig : 1; // 阻塞信号标记
uint wasDeleted : 1; // 是否参数标记
uint ownObjectName : 1; // 是否含有对象名标记
uint sendChildEvents : 1; // 发送到子对象时间标记
uint receiveChildEvents : 1; // 接受子对象时间标记
uint inEventHandler : 1; // 是否有事件句柄标记
uint inThreadChangeEvent : 1; // 线程更改时间标记
//是否有守护标记
uint hasGuards : 1; //true iff there is one or more QPointer attached to this object
uint unused : 22; // 保留
int postedEvents; // 发送的数据
QMetaObject *metaObject; // assert dynamic // 元对象
};
QObjectData保留一些了基本的数据信息
view plain
#define Q_DECLARE_PUBLIC(Class) \
inline Class* q_func() { return static_cast(q_ptr); } \
inline const Class* q_func() const { return static_cast(q_ptr); } \
friend class Class;
在元对象中获取类名和父类的方式很简单,直接即可。
view plain
inline const char *QMetaObject::className() const
{ return d.stringdata; }
inline const QMetaObject *QMetaObject::superClass() const
{ return d.superdata; }
元对象中cast函数的实现
view plain
QObject *QMetaObject::cast(QObject *obj) const
{
if (obj) {
const QMetaObject *m = obj->metaObject();
do {
if (m == this)
return const_cast(obj);
} while ((m = m->d.superdata));
}
return 0;
}
如果对象obj存在,则对每一个obj的父类的源对象进行转换,如果是当前的元对象,则进行返回,否则返回0,也就是cast函数是在obj中查找当前元对象所在的QObject对象。