所有QObject的派生类在官方文档中都推荐在头文件中放置宏Q_OBJECT,那么该宏到底为我们做了哪些工作?在qobjectdef.h中有下面的代码:

  1. #define Q_OBJECT \
  2. public: \
  3. Q_OBJECT_CHECK \
  4. static const QMetaObject staticMetaObject; \
  5. Q_OBJECT_GETSTATICMETAOBJECT \
  6. virtual const QMetaObject *metaObject() const; \
  7. virtual void *qt_metacast(const char *); \
  8. QT_TR_FUNCTIONS \
  9. virtual int qt_metacall(QMetaObject::Call, int, void **); \
  10. private:

首先定义了一个Q_OBJECT_CHECK宏,这个宏在Q_OBJECT宏的上方定义:

  1. #define Q_OBJECT_CHECK \
  2. template <typename T> inline void qt_check_for_QOBJECT_macro(const T &_q_argument) const \
  3. { int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument); i = i; }

Q_OBJECT_CHECK实现了一个模板函数,该函数调用了qYouForgotTheQ_OBJECT_Macro的函数,qYouForgotTheQ_OBJECT_Macro在宏Q_OBJECT_CHECK下面有定义:

  1. template <typename T>
  2. inline int qYouForgotTheQ_OBJECT_Macro(T, T) { return 0; }
  3. template <typename T1, typename T2>
  4. inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {}

从返回值情况上可以看到,调用的是有int返回值的那个模板函数。但是很不明白,为什么之后还要添加一句 i=i?,刨根之后,发现Q_OBJECT_CHECK宏并没有做什么工作。

然后Q_OBJECT又帮我们定义了一个静态的元对象,

  1. static const QMetaObject staticMetaObject; \
  2. Q_OBJECT_GETSTATICMETAOBJECT \

Q_OBJECT_GETSTATICMETAOBJECT宏从名字上看就是为了获取这个元对象,确实在定义了Q_NO_DATA_RELOCATION宏的情况下,Q_OBJECT_GETSTATICMETAOBJECT宏就为我们定义了获取静态元对象的方法。

  1. #ifdef Q_NO_DATA_RELOCATION
  2. #define Q_OBJECT_GETSTATICMETAOBJECT static const QMetaObject &getStaticMetaObject();
  3. #else
  4. #define Q_OBJECT_GETSTATICMETAOBJECT
  5. #endif

之后Q_OBJECT宏又给我们定义了连个虚函数用来获取元对象指针和设置源对象。

  1. virtual const QMetaObject *metaObject() const; \
  2. virtual void *qt_metacast(const char *); \

而定义的  QT_TR_FUNCTIONS 则表示是否支持I18N。

  1. #ifndef QT_NO_TRANSLATION
  2. # ifndef QT_NO_TEXTCODEC
  3. // full set of tr functions
  4. // ### Qt 5: merge overloads
  5. # define QT_TR_FUNCTIONS \
  6. static inline QString tr(const char *s, const char *c = 0) \
  7. { return staticMetaObject.tr(s, c); } \
  8. static inline QString trUtf8(const char *s, const char *c = 0) \
  9. { return staticMetaObject.trUtf8(s, c); } \
  10. static inline QString tr(const char *s, const char *c, int n) \
  11. { return staticMetaObject.tr(s, c, n); } \
  12. static inline QString trUtf8(const char *s, const char *c, int n) \
  13. { return staticMetaObject.trUtf8(s, c, n); }
  14. # else
  15. // no QTextCodec, no utf8
  16. // ### Qt 5: merge overloads
  17. # define QT_TR_FUNCTIONS \
  18. static inline QString tr(const char *s, const char *c = 0) \
  19. { return staticMetaObject.tr(s, c); } \
  20. static inline QString tr(const char *s, const char *c, int n) \
  21. { return staticMetaObject.tr(s, c, n); }
  22. # endif
  23. #else
  24. // inherit the ones from QObject
  25. # define QT_TR_FUNCTIONS
  26. #endif

只要有所实现,tr的方法就通过静态对象staticMetaObject的tr方法来实现。最后Q_OBJECT又定义了一个虚函数

  1. virtual int qt_metacall(QMetaObject::Call, int, void **);

看名字定义,应该是用来对元对象的调用。

合起来看所有的Q_OBJECT定义,都是为了操作元对象,并没有所谓的信号和槽,属性等内容,很显然,QObject对象能够支持这些功能,必然是通过QMetaObject这个元对象来实现的。尽管QMetaObject对象的实现有些庞大,但这个是所有的QOBject中最核心的一个实现,因此需要仔细分析该对象的每个定义:

  1. struct Q_CORE_EXPORT QMetaObject
  2. {
  3. const char *className() const;                                    // 类名
  4. const QMetaObject *superClass() const;                            // 父类的元对象
  5. QObject *cast(QObject *obj) const;                                // 强制一个对象
  6. #ifndef QT_NO_TRANSLATION
  7. // ### Qt 4: Merge overloads
  8. QString tr(const char *s, const char *c) const;                       // 翻译函数
  9. QString trUtf8(const char *s, const char *c) const;
  10. QString tr(const char *s, const char *c, int n) const;
  11. QString trUtf8(const char *s, const char *c, int n) const;
  12. #endif // QT_NO_TRANSLATION
  13. int methodOffset() const;                                 // 方法偏移量
  14. int enumeratorOffset() const;                             // 枚举偏移量
  15. int propertyOffset() const;                                   // 属性偏移量
  16. int classInfoOffset() const;                                  // 类信息数目
  17. int constructorCount() const;                             // 构造函数数目
  18. int methodCount() const;                                  // 方法数目
  19. int enumeratorCount() const;                              // 枚举数据
  20. int propertyCount() const;                                    // 属性数目
  21. int classInfoCount() const;                                   // 类信息数目
  22. int indexOfConstructor(const char *constructor) const;            // 构函函数索引
  23. int indexOfMethod(const char *method) const;                  // 方法索引
  24. int indexOfSignal(const char *signal) const;                  // 信号量索引
  25. int indexOfSlot(const char *slot) const;                      // 槽索引
  26. int indexOfEnumerator(const char *name) const;                // 枚举索引
  27. int indexOfProperty(const char *name) const;                  // 属性索引
  28. int indexOfClassInfo(const char *name) const;                 // 类信息索引
  29. QMetaMethod constructor(int index) const;                 // 构造方法
  30. QMetaMethod method(int index) const;                      // 方法
  31. QMetaEnum enumerator(int index) const;                        // 枚举
  32. QMetaProperty property(int index) const;                      // 属性
  33. QMetaClassInfo classInfo(int index) const;                    // 类属性信息
  34. QMetaProperty userProperty() const;                           // 用户属性
  35. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  36. static bool checkConnectArgs(const char *signal, const char *method);
  37. static QByteArray normalizedSignature(const char *method);
  38. static QByteArray normalizedType(const char *type);
  39. // internal index-based connect
  40. static bool connect(const QObject *sender, int signal_index,
  41. const QObject *receiver, int method_index,
  42. int type = 0, int *types = 0);
  43. // internal index-based disconnect
  44. static bool disconnect(const QObject *sender, int signal_index,
  45. const QObject *receiver, int method_index);
  46. static bool disconnectOne(const QObject *sender, int signal_index,
  47. const QObject *receiver, int method_index);
  48. // internal slot-name based connect
  49. static void connectSlotsByName(QObject *o);
  50. // internal index-based signal activation
  51. static void activate(QObject *sender, int signal_index, void **argv); //obsolete
  52. static void activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv); //obsolete
  53. static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv);
  54. static void activate(QObject *sender, const QMetaObject *, int from_local_signal_index, int to_local_signal_index, void **argv); //obsolete
  55. // internal guarded pointers
  56. static void addGuard(QObject **ptr);
  57. static void removeGuard(QObject **ptr);
  58. static void changeGuard(QObject **ptr, QObject *o);
  59. static bool invokeMethod(QObject *obj, const char *member,
  60. Qt::ConnectionType,
  61. QGenericReturnArgument ret,
  62. QGenericArgument val0 = QGenericArgument(0),
  63. QGenericArgument val1 = QGenericArgument(),
  64. QGenericArgument val2 = QGenericArgument(),
  65. QGenericArgument val3 = QGenericArgument(),
  66. QGenericArgument val4 = QGenericArgument(),
  67. QGenericArgument val5 = QGenericArgument(),
  68. QGenericArgument val6 = QGenericArgument(),
  69. QGenericArgument val7 = QGenericArgument(),
  70. QGenericArgument val8 = QGenericArgument(),
  71. QGenericArgument val9 = QGenericArgument());
  72. static inline bool invokeMethod(QObject *obj, const char *member,
  73. QGenericReturnArgument ret,
  74. QGenericArgument val0 = QGenericArgument(0),
  75. QGenericArgument val1 = QGenericArgument(),
  76. QGenericArgument val2 = QGenericArgument(),
  77. QGenericArgument val3 = QGenericArgument(),
  78. QGenericArgument val4 = QGenericArgument(),
  79. QGenericArgument val5 = QGenericArgument(),
  80. QGenericArgument val6 = QGenericArgument(),
  81. QGenericArgument val7 = QGenericArgument(),
  82. QGenericArgument val8 = QGenericArgument(),
  83. QGenericArgument val9 = QGenericArgument())
  84. {
  85. return invokeMethod(obj, member, Qt::AutoConnection, ret, val0, val1, val2, val3,
  86. val4, val5, val6, val7, val8, val9);
  87. }
  88. static inline bool invokeMethod(QObject *obj, const char *member,
  89. Qt::ConnectionType type,
  90. QGenericArgument val0 = QGenericArgument(0),
  91. QGenericArgument val1 = QGenericArgument(),
  92. QGenericArgument val2 = QGenericArgument(),
  93. QGenericArgument val3 = QGenericArgument(),
  94. QGenericArgument val4 = QGenericArgument(),
  95. QGenericArgument val5 = QGenericArgument(),
  96. QGenericArgument val6 = QGenericArgument(),
  97. QGenericArgument val7 = QGenericArgument(),
  98. QGenericArgument val8 = QGenericArgument(),
  99. QGenericArgument val9 = QGenericArgument())
  100. {
  101. return invokeMethod(obj, member, type, QGenericReturnArgument(), val0, val1, val2,
  102. val3, val4, val5, val6, val7, val8, val9);
  103. }
  104. static inline bool invokeMethod(QObject *obj, const char *member,
  105. QGenericArgument val0 = QGenericArgument(0),
  106. QGenericArgument val1 = QGenericArgument(),
  107. QGenericArgument val2 = QGenericArgument(),
  108. QGenericArgument val3 = QGenericArgument(),
  109. QGenericArgument val4 = QGenericArgument(),
  110. QGenericArgument val5 = QGenericArgument(),
  111. QGenericArgument val6 = QGenericArgument(),
  112. QGenericArgument val7 = QGenericArgument(),
  113. QGenericArgument val8 = QGenericArgument(),
  114. QGenericArgument val9 = QGenericArgument())
  115. {
  116. return invokeMethod(obj, member, Qt::AutoConnection, QGenericReturnArgument(), val0,
  117. val1, val2, val3, val4, val5, val6, val7, val8, val9);
  118. }
  119. QObject *newInstance(QGenericArgument val0 = QGenericArgument(0),
  120. QGenericArgument val1 = QGenericArgument(),
  121. QGenericArgument val2 = QGenericArgument(),
  122. QGenericArgument val3 = QGenericArgument(),
  123. QGenericArgument val4 = QGenericArgument(),
  124. QGenericArgument val5 = QGenericArgument(),
  125. QGenericArgument val6 = QGenericArgument(),
  126. QGenericArgument val7 = QGenericArgument(),
  127. QGenericArgument val8 = QGenericArgument(),
  128. QGenericArgument val9 = QGenericArgument()) const;
  129. enum Call {
  130. InvokeMetaMethod,
  131. ReadProperty,
  132. WriteProperty,
  133. ResetProperty,
  134. QueryPropertyDesignable,
  135. QueryPropertyScriptable,
  136. QueryPropertyStored,
  137. QueryPropertyEditable,
  138. QueryPropertyUser,
  139. CreateInstance
  140. };
  141. int static_metacall(Call, int, void **) const;
  142. static int metacall(QObject *, Call, int, void **);
  143. #ifdef QT3_SUPPORT
  144. QT3_SUPPORT const char *superClassName() const;
  145. #endif
  146. struct { // private data
  147. const QMetaObject *superdata;                         // 父类
  148. const char *stringdata;                               // 类名
  149. const uint *data;                                     // 任意指向数据的指针
  150. const void *extradata;                                    // 扩展数据
  151. } d;
  152. };

QMetaObject就内部一个结构体对象,包含了四个部分,分别是父类对象,自己元对象的名称,以及一个指针任意值的指针数据和扩展数据,一般情况下,d.data表示的是QMetaObjectPrivate对象指针,在priv函数中可以找到一些痕迹:

  1. static inline const QMetaObjectPrivate *priv(const uint* data)
  2. { return reinterpret_cast<const QMetaObjectPrivate*>(data); }

按照Qt的实现惯例,使用Private对象做一些具体的工作,于是就有了QMetaObjectPrivate和QObjectPrivate

  1. struct QMetaObjectPrivate                               // 注意是一个结构体
  2. {
  3. int revision;                                         // 版本
  4. int className;                                        // 类名,注意类型
  5. int classInfoCount, classInfoData;                        // 类信息数据和数量
  6. int methodCount, methodData;                          // 方法数据和数量
  7. int propertyCount, propertyData;                      // 属性数据和数量
  8. int enumeratorCount, enumeratorData;                  // 枚举数据和数量
  9. int constructorCount, constructorData; //since revision 2     // 构造函数数据和数量
  10. int flags; //since revision 3                             // 标记
  11. int signalCount; //since revision 4                       // 信号量数目
  12. // revision 5 introduces changes in normalized signatures, no new members
  13. // 从元数据中获取QMetaObjectPrivate对象指针,从data中得到!!
  14. static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
  15. { return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); }
  16. static int indexOfSignalRelative(const QMetaObject **baseObject,
  17. const char* name,
  18. bool normalizeStringData);
  19. static int indexOfSlot(const QMetaObject *m,
  20. const char *slot,
  21. bool normalizeStringData);
  22. static int originalClone(const QMetaObject *obj, int local_method_index);
  23. #ifndef QT_NO_QOBJECT
  24. //defined in qobject.cpp
  25. enum DisconnectType { DisconnectAll, DisconnectOne };
  26. static bool connect(const QObject *sender, int signal_index,
  27. const QObject *receiver, int method_index,
  28. int type = 0, int *types = 0);
  29. static bool disconnect(const QObject *sender, int signal_index,
  30. const QObject *receiver, int method_index,
  31. DisconnectType = DisconnectAll);
  32. static inline bool disconnectHelper(QObjectPrivate::Connection *c,
  33. const QObject *receiver, int method_index,
  34. QMutex *senderMutex, DisconnectType);
  35. #endif
  36. };

==================================================================

  1. class Q_CORE_EXPORT QObjectPrivate : public QObjectData
  2. {
  3. Q_DECLARE_PUBLIC(QObject)
  4. public:
  5. struct ExtraData                      // 定义额外数据
  6. {
  7. ExtraData() {}
  8. #ifndef QT_NO_USERDATA
  9. QVector<QObjectUserData *> userData;
  10. #endif
  11. QList<QByteArray> propertyNames;                    // 属性名列表
  12. QList<QVariant> propertyValues;                     // 属性值
  13. };
  14. struct Connection                                     // 定义连接信息
  15. {
  16. QObject *sender;                                  // 发送者
  17. QObject *receiver;                                    // 接受者
  18. int method;                                           // 方法
  19. uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
  20. QBasicAtomicPointer<int> argumentTypes;             // 参数类型
  21. // The next pointer for the singly-linked ConnectionList
  22. Connection *nextConnectionList;                       // 下一个连接对象列表
  23. //senders linked list
  24. Connection *next;                                 // 下一个连接
  25. Connection **prev;                                    // 上一个连接
  26. ~Connection();
  27. };
  28. // ConnectionList is a singly-linked list
  29. struct ConnectionList {                                   // 定义连接列表
  30. ConnectionList() : first(0), last(0) {}
  31. Connection *first;                                    // 连接首
  32. Connection *last;                                 // 连接尾
  33. };
  34. struct Sender                                         // 定义发送者
  35. {
  36. QObject *sender;                                  // 发送者
  37. int signal;                                           // 信号
  38. int ref;                                              // 引用计数
  39. };
  40. QObjectPrivate(int version = QObjectPrivateVersion);
  41. virtual ~QObjectPrivate();
  42. void deleteChildren();                                        // 删除所有子节点
  43. void setParent_helper(QObject *);                             // 设置父节点
  44. void moveToThread_helper();                                   // 转到某个线程中
  45. void setThreadData_helper(QThreadData *currentData, QThreadData *targetData); // 设置线程数据
  46. void _q_reregisterTimers(void *pointer);                          // 设置注册时间
  47. bool isSender(const QObject *receiver, const char *signal) const; // 判断信号量是否为发送者
  48. QObjectList receiverList(const char *signal) const;               // 接受信号的对象列表
  49. QObjectList senderList() const;                               // 发出信息列表
  50. void addConnection(int signal, Connection *c);                // 添加一个信号连接
  51. void cleanConnectionLists();                              // 清理连接列表
  52. #ifdef QT3_SUPPORT
  53. void sendPendingChildInsertedEvents();
  54. void removePendingChildInsertedEvents(QObject *child);
  55. #endif
  56. static inline Sender *setCurrentSender(QObject *receiver,
  57. Sender *sender);          // 设置当前发送者
  58. static inline void resetCurrentSender(QObject *receiver,
  59. Sender *currentSender,
  60. Sender *previousSender);   // 重置当前发送者
  61. static int *setDeleteWatch(QObjectPrivate *d, int *newWatch); // 设置删除监听
  62. static void resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch);  // 重置删除监听
  63. static void clearGuards(QObject *);                   // 清除管理者
  64. static QObjectPrivate *get(QObject *o) {          // 从QObject对象中获取QObjectPrivate
  65. return o->d_func();
  66. }
  67. int signalIndex(const char *signalName) const;            // 信号索引
  68. inline bool isSignalConnected(uint signalIdx) const;      // 判断是否为信号连接
  69. public:
  70. QString objectName;                                   // 对象名字
  71. ExtraData *extraData;   // extra data set by the user     // 额外数据
  72. QThreadData *threadData; // id of the thread that owns the object     // 线程数据
  73. QObjectConnectionListVector *connectionLists;                 // 连接列表数组
  74. Connection *senders;    // linked list of connections connected to this object  // 发送者连接
  75. Sender *currentSender;  // object currently activating the object         // 当前发送者
  76. mutable quint32 connectedSignals[2];                      // 连接信号
  77. #ifdef QT3_SUPPORT
  78. QList<QObject *> pendingChildInsertedEvents;
  79. #else
  80. // preserve binary compatibility with code compiled without Qt 3 support
  81. // keeping the binary layout stable helps the Qt Creator debugger
  82. void *unused;                                     // 保留
  83. #endif
  84. QList<QPointer<QObject> > eventFilters;
  85. union {
  86. QObject *currentChildBeingDeleted;                // 当前子节点被删除
  87. QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
  88. };
  89. // these objects are all used to indicate that a QObject was deleted
  90. // plus QPointer, which keeps a separate list
  91. QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount; // 共享引用计数
  92. int *deleteWatch;         // 删除监听者
  93. };

QObjectPrivate从QObjectData派生下来:

  1. class
  2. #if defined(__INTEL_COMPILER) && defined(Q_OS_WIN)
  3. Q_CORE_EXPORT
  4. #endif
  5. QObjectData {
  6. public:
  7. virtual ~QObjectData() = 0;
  8. QObject *q_ptr;                               // 当前指向的QOBject
  9. QObject *parent;                              // 指向的QObject父类
  10. QObjectList children;                         // 孩儿们
  11. uint isWidget : 1;                                // 是否为widget的标记
  12. uint pendTimer : 1;                           // 开启时钟
  13. uint blockSig : 1;                                // 阻塞信号标记
  14. uint wasDeleted : 1;                          // 是否参数标记
  15. uint ownObjectName : 1;                       // 是否含有对象名标记
  16. uint sendChildEvents : 1;                     // 发送到子对象时间标记
  17. uint receiveChildEvents : 1;                  // 接受子对象时间标记
  18. uint inEventHandler : 1;                      // 是否有事件句柄标记
  19. uint inThreadChangeEvent : 1;                 // 线程更改时间标记
  20. //是否有守护标记
  21. uint hasGuards : 1; //true iff there is one or more QPointer attached to this object
  22. uint unused : 22;                             // 保留
  23. int postedEvents;                             // 发送的数据
  24. QMetaObject *metaObject; // assert dynamic            // 元对象
  25. };

QObjectData保留一些了基本的数据信息

  1. #define Q_DECLARE_PUBLIC(Class)                                   \
  2. inline Class* q_func() { return static_cast<Class *>(q_ptr); } \
  3. inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \
  4. friend class Class;

在元对象中获取类名和父类的方式很简单,直接即可。

  1. inline const char *QMetaObject::className() const
  2. { return d.stringdata; }
  3. inline const QMetaObject *QMetaObject::superClass() const
  4. { return d.superdata; }

元对象中cast函数的实现

view plainprint?

  1. QObject *QMetaObject::cast(QObject *obj) const
  2. {
  3. if (obj) {
  4. const QMetaObject *m = obj->metaObject();
  5. do {
  6. if (m == this)
  7. return const_cast<QObject*>(obj);
  8. } while ((m = m->d.superdata));
  9. }
  10. return 0;
  11. }

如果对象obj存在,则对每一个obj的父类的源对象进行转换,如果是当前的元对象,则进行返回,否则返回0,也就是cast函数是在obj中查找当前元对象所在的QObject对象。

Q_OBJECT的更多相关文章

  1. Qt - 错误总结 - 在自定义类头文件中添加Q_OBJECT 编译时报错(undefined reference to ‘vtable for xxThread)

    错误提示:在添加的QThread子类头文件添加Q_OBJECT时,编译程序,出现"undefined reference to 'vtable for xxThread'"错误提示 ...

  2. qt中添加Q_OBJECT报错的问题

    在qt编写的过程中添加Q_OBJECT后发现老是报错的问题 编译后老是报undefined reference to vtable for "xxx"的错误,后来发现在xxx.pr ...

  3. QT宏 Q_OBJECT,explicit, QHostAddress, quint, emit

    QT相關 一. 參考: 1.宏Q_OBJECT 二. explicit struct constrcution 三. QHostAddress Detailed Description: The QH ...

  4. 气死人不偿命,Q_OBJECT导致的C++报错,而且还看不明白(#ifdef没控制好,导致什么都不认识了)

    为了代码可以同时适应VC++和MingW编译器,我改动了我的代码,变成: #ifdef _MSC_VER #pragma comment(lib, "crypt32.lib") / ...

  5. cmake+qt+qtcreator的配置,解决Q_OBJECT的问题

    1.如果在编译qt项目的时候,一般头文件里都有Q_OBJECT,但是用cmake来编译的时候,就会报错,那么怎么解决呢? 解决的办法就是要在cmake里面写好配置 命令,再编译的时候,就不会报错了,写 ...

  6. Qt错误:类中使用Q_OBJECT宏导致undefined reference to vtable for "xxx::xxx"错误的原因和解决方法

    在进行Qt编程的时候,有时候会将类的定义和实现都写在源文件中,如果同时在该类中使用信号/槽,那么可能就会遇到 undefined reference to vtable for "xxx:: ...

  7. Qt5 在添加 Q_OBJECT 后发现编译出错的原因

    在 Qt 编写过程中,如多线程使用信号槽时,需要添加 Q_OBJECT,但是在添加之后发现编译老会出错.如下: class ThreadSxxx : public QThread { Q_OBJECT ...

  8. 读QT5.7源码(三)Q_OBJECT 和QMetaObject

    Qt meta-object系统基于三个方面:  1.QObject提供一个基类,方便派生类使用meta-object系统的功能:  2.Q_OBJECT宏,在类的声明体内激活meta-object功 ...

  9. Quest for sane signals in Qt - step 1 (hand coding a Q_OBJECT)

    探索qt的信号ref: http://crazyeddiecpp.blogspot.hk/2011/01/quest-for-sane-signals-in-qt-step-1.html If it ...

随机推荐

  1. Redis配置文件参数说明

    Redis配置文件参数说明   1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 daemonize no 2. 当Redis以守护进程方式运行时,Redis ...

  2. 42、lucene和机器学习进行全文搜索,并排序

    package com.lucene.test; import java.io.BufferedInputStream; import java.io.File; import java.io.Fil ...

  3. 动态设置和访问cxgrid列的Properties(转)

    原文:http://www.cnblogs.com/hnxxcxg/archive/2010/05/24/2940711.html 动态设置和访问cxgrid列的Properties 设置: cxGr ...

  4. Des加解密算法

    class DesHelper    {        /// <summary>        /// DES加密方法        /// </summary>       ...

  5. web聊天室

    开发一个web聊天室 功能需求: 1.用户可以与好友一对一聊天 2.群聊 所需知识 1.Django 2.bootstrap 3.CSS 4.ajax 涉及到的新的知识点 1.如果设计表结构的时候,一 ...

  6. Roguelike 相关知识

    here is the link here

  7. 关于设置anroid系统时间

    我最近在做一个项目需要设置android系统时间,设置android 时间往往缺少权限,看到http://blog.csdn.net/kakaxi1o1/article/details/3687278 ...

  8. 用于模式匹配的String方法

    String支持四种使用正则表达式的方法. 1.search()返回第一个与之匹配的子串的起始位置,找不到返回-1.search()参数是一个正则表达式,如果参数不是正则表达式,则会先通过RegExp ...

  9. 删除表空间的时候遇到的问题:ORA-02429: 无法删除用于强制唯一/主键的索引

    今天打算删除orcale数据库中无用的表空间,发现报错,查资料删除,写个过程留着备用.1.drop tablespace dldata INCLUDING CONTENTS CASCADE CONST ...

  10. Struts2 有关于无法正常的使用通配符

    今天使用struts 2.3.4版本,做了一个通配符的小测试,结果其他的Action都能正常的使用,但是使用通配符的Action不能正常的使用.网上找了很久,最后发现,貌似strust2.3版本以上的 ...