QObject
QObeject 时Qt的核心之一,用于实现QT的元对象类型和信号槽等,体现了元编程的思想
//每个QObject 都会有一个 QObjectData 保护数据,用来标识这个QObject的数据变量
class QObjectData {
public:
virtual ~QObjectData() = 0;
QObject *q_ptr; //对象自身的指针
QObject *parent; //父对象指针
QObjectList children; //子对象列表
uint isWidget : 1; //是否是QWidget
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 unused : 23;
int postedEvents; //已发布事件数
};
// 用户自定义数据
struct ExtraData
{
#ifndef QT_NO_USERDATA
QVector<QObjectUserData *> userData;
#endif
QList<QByteArray> propertyNames;
QList<QVariant> propertyValues;
};
这个结构体代表一个信号的发送者
struct Sender
{
QObject *sender; //发送对象
int signal; //信号索引,如发送者有三个信号,就分别标记为0,1,2
int ref; //引用计数 有多少个连接使用这个发送者信号
};
//这个结构代表一个信号与槽的连接
struct Connection
{
QObject *receiver; //接收对象
int method; //槽方法索引
uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking //连接方式
QBasicAtomicPointer<int> argumentTypes; //参数类型
};
QObjectPrivate 类用这两个结构体来对象的信号和槽的连接。
typedef QList<Connection> ConnectionList;
QObjectConnectionListVector *connectionLists;
QList<Sender> senders;
//这个 类代表一个元调用事件,用于在事件循环中触发对象的信号。
class Q_CORE_EXPORT QMetaCallEvent : public QEvent
{
public:
QMetaCallEvent(int id, const QObject *sender, int signalId,
int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0);
~QMetaCallEvent();
inline int id() const { return id_; }
inline const QObject *sender() const { return sender_; }
inline int signalId() const { return signalId_; }
inline void **args() const { return args_; }
virtual int placeMetaCall(QObject *object);
private:
int id_; //事件id
const QObject *sender_; //信号发送者
int signalId_; //发送对象信号索引,代表这个对象发发出多少个信号。
int nargs_; //参数数量
int *types_; //参数类型
void **args_; //参数列表
QSemaphore *semaphore_; //保证信号槽同步信号量
};
//这个函数主要用于将信号槽连接的参数类型转换为整型类型,以便于 Qt 可以对它们进行序列化和反序列化,从而支持信号槽跨线程连接。
//函数内部通过 for 循环,遍历 typeNames 中的每一个参数类型名称,将其转换为相应的整型类型并存储在整型数组 types 中。如果转换失败,即该类型名称未被注册,将会输出一条警告信息并返回一个空指针。这个函数的使用场景是,在某些Qt的连接(connect)调用中,需要提供参数的类型信息。通过传入类型名列表,可以获取到对应的类型ID数组,从而完成connect。
//Direct Connection,Queued Connection,Auto Connection,Blocking Queued Connection, 四种连接方式
static int *queuedConnectionTypes(const QList<QByteArray> &typeNames)
{
int *types = static_cast<int *>(qMalloc((typeNames.count() + 1) * sizeof(int)));
for (int i = 0; i < typeNames.count(); ++i) {
const QByteArray typeName = typeNames.at(i);
if (typeName.endsWith('*'))
types[i] = QMetaType::VoidStar;
else
types[i] = QMetaType::type(typeName);
if (!types[i]) {
qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
"(Make sure '%s' is registered using qRegisterMetaType().)",
typeName.constData(), typeName.constData());
qFree(types);
return 0;
}
}
types[typeNames.count()] = 0;
return types;
}
QObjectData 虚基类,包含了一些 QObject的私有数据成员。
QObjectData 实现继承 QObjectData是 QObject 类的内部私有实现类, 用于存储QObject 对象的私有数据。
QObject 的父对象(parent)
QObject 的对象名称(objectName)
QObject 的对象树结构(children)
QObject 的信号槽连接关系(sender、receiver、connectionLists)
QObject 的元对象系统(metaObject)
QObject 的线程和事件循环(threadData)
QObjectPrivate 还实现了 QObject 对象的信号槽机制、动态属性、事件过滤器等功能的核心实现。
QObjectPrivate::QObjectPrivate(int version) //构造函数版本兼容性
//如何deleteWatch 不为空,这个是用于QObject的自动删除机制,当QObject被析构时,如果deleteWatch被设置,则说明这个QObject是自动删除的,将deleteWatch设置为1表示这个自动删除的对象已经被析构了。
//支持QObject的自动删除机制,通过deleteWatch标记自动删除的QObject已被析构。
//析构函数保证了QObject对象在析构时,相关的清理工作都会被执行,不会导致资源泄露等问题
QObjectPrivate::~QObjectPrivate()
{
if (deleteWatch)
*deleteWatch = 1;
#ifndef QT_NO_USERDATA
if (extraData)
qDeleteAll(extraData->userData);
delete extraData;
#endif
}
int *QObjectPrivate::setDeleteWatch(QObjectPrivate *d, int *w)
//设置d的deleteWatch 为w,并返回旧的指针
void QObjectPrivate::resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch) {
if (!deleteWatch)
d->deleteWatch = oldWatch;
if (oldWatch)
*oldWatch = deleteWatch;
}
//QObjectConnectionListVector 是一个向量(QVector),它存储了 QObject 的信号与槽连接信息。
//通过QVector存储每个信号的连接列表信息,索引对应于信号的元方法索引。
//allsignals用于存储所有信号的连接信息,这是为了优化信号发射时的查找速度。
//orphaned和inUse用于管理连接列表的生命期。变0可以表示父信号已经被消除,或者无连接了,就可以删除这个信号和槽了。
class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList> // 存储每个信号的连接信息
{
public:
bool orphaned; //是否为孤立连接,父对象已销毁
bool dirty; //表示连接列表是否需要重新计算引用计数
int inUse; //该连接列表的引用计数,0时可以删除(发送和接收都计数)
QObjectPrivate::ConnectionList allsignals; //存储所有信号的连接信息
QObjectConnectionListVector()
: QVector<QObjectPrivate::ConnectionList>(), orphaned(false), dirty(false), inUse(0)
{ }
const QObjectPrivate::ConnectionList &at(int at) const
{
if (at < 0)
return allsignals;
return QVector<QObjectPrivate::ConnectionList>::at(at);
}
QObjectPrivate::ConnectionList &operator[](int at)
{
if (at < 0)
return allsignals;
return QVector<QObjectPrivate::ConnectionList>::operator[](at);
}
};
//检查一个QObject 对象是否已经连接了指定信号 signal 到接收对象 receiver。
bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const
//获取指定信号的所有连接对象
//当信号被触发时,会获取这个函数获取所有的接收者。
QObjectList QObjectPrivate::receiverList(const char *signal) const
//获取连接到当前对象的所有发送对象,在disconnect 时,未指定 发送者,需要断开与所有发送者的连接
QObjectList QObjectPrivate::senderList() const
// signal 信号为中心,存储连接到这个信号的所有接收者信息的列表
// 添加 signal 所连接的 槽函数的信息
void QObjectPrivate::addConnection(int signal, Connection *c)
// 将 receiver 从 signal 的连接队列中移除
void QObjectPrivate::removeReceiver(int signal, QObject *receiver)
//清理连接列表,移除无效的连接。
void QObjectPrivate::cleanConnectionLists()
//增加槽函数的连接信号的发送者信息引用。
void QObjectPrivate::refSender(QObject *sender, int signal)
////减少槽函数连接信号的信息发送者的索引
void QObjectPrivate::derefSender(QObject *sender, int signal)
//静态函数
//更改 receiver 的 发送者 为sender, 返回旧 的发送者
QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver,
Sender *sender)
//静态函数
//更改receiver 的当前发送对象 currentSender指针
void QObjectPrivate::resetCurrentSender(QObject *receiver,
Sender *currentSender,
Sender *previousSender)
QMetaObject 元对象类:对象的元信息,对象的属性,方法和信号
//管理一个 guard 的东西
//**ptr: 它指向的就是一个QObject *指针,该指针再指向一个QObject对象
//ptr 本身是一个 指向QObject指针的指针,它间接指向一个QObject对象。
void QMetaObject::addGuard(QObject **ptr)
{
if (!*ptr)
return;
GuardHash *hash = guardHash();
if (!hash) {
*ptr = 0;
return;
}
QMutexLocker locker(guardHashLock());
hash->insert(*ptr, ptr);
}
/*!\internal
*/
void QMetaObject::removeGuard(QObject **ptr)
{
if (!*ptr)
return;
GuardHash *hash = guardHash();
if (!hash)
return;
QMutexLocker locker(guardHashLock());
GuardHash::iterator it = hash->find(*ptr);
const GuardHash::iterator end = hash->end();
for (; it.key() == *ptr && it != end; ++it) {
if (it.value() == ptr) {
(void) hash->erase(it);
break;
}
}
}
/*!\internal
*/
void QMetaObject::changeGuard(QObject **ptr, QObject *o)
{
GuardHash *hash = guardHash();
if (!hash) {
*ptr = 0;
return;
}
QMutexLocker locker(guardHashLock());
if (*ptr) {
GuardHash::iterator it = hash->find(*ptr);
const GuardHash::iterator end = hash->end();
for (; it.key() == *ptr && it != end; ++it) {
if (it.value() == ptr) {
(void) hash->erase(it);
break;
}
}
}
*ptr = o;
if (*ptr)
hash->insert(*ptr, ptr);
}
//清除一个 对象的声明周期
void QObjectPrivate::clearGuards(QObject *object)
QMetaCallEvent 是一个用于在事件队列中调用Qt元对象方法的事件类,它用于在接收到信号后,将携带参数的事件插入到目标对象的事件队列中,并等待事件被处理。
//在事件循环中执行目标QOBject对象的实际槽函数调用
//允许跨线程进行对QObject对象的异步调用
1. 它在事件循环中被调用,用于执行目标QObject对象的实际槽函数调用。
2. 它调用QObject::qt_metacall()完成实际的调用,传入必要的参数。
3. 它与events()->postEvent()配合,实现了对QObject的异步调用,解耦了QObject与事件循环。
int QMetaCallEvent::placeMetaCall(QObject *object)
{
return object->qt_metacall(QMetaObject::InvokeMetaMethod, id_, args_);
}
QObject Qt对象模型的核心,用于无缝对象通信的机制,称为信号和槽。
//给定的父对象parent下查找名称为name、类型为type的子对象。
void *qt_find_obj_child(QObject *parent, const char *type, const QString &name)
{
QObjectList list = parent->children();
if (list.size() == 0) return 0;
for (int i = 0; i < list.size(); ++i) {
QObject *obj = list.at(i);
if (name == obj->objectName() && obj->inherits(type))
return obj;
}
return 0;
}
//多线程程序中创建父子关系时进行检查,确保在同一线程中创建对象,避免线程安全问题
static bool check_parent_thread(QObject *parent,
QThreadData *parentThreadData,
QThreadData *currentThreadData)
{
if (parent && parentThreadData != currentThreadData) {
QThread *parentThread = parentThreadData->thread;
QThread *currentThread = currentThreadData->thread;
qWarning("QObject: Cannot create children for a parent that is in a different thread.\n"
"(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)",
parent->metaObject()->className(),
parent,
parentThread ? parentThread->metaObject()->className() : "QThread",
parentThread,
currentThread ? currentThread->metaObject()->className() : "QThread",
currentThread);
return false;
}
return true;
}
QObject::QObject(QObject *parent) //构造函数,公有。指定父对象
: d_ptr(new QObjectPrivate)
//protected 构造对象
QObject::QObject(QObjectPrivate &dd, QObject *parent)
//析构函数,释放信号连接的槽函数对象信息,释放槽函数连接的信号对象资源,定时器,对象树,事件等
QObject::~QObject()
QString QObject::objectName() const //返回当前对象名称
// QObject的事件处理函数。它接收所有的事件,并根据事件类型进行相应的处理
// 对象有关事件的统一入口
bool QObject::event(QEvent *e)
// 虚函数,用户可以这个函数,处理定时器相关事件
void QObject::timerEvent(QTimerEvent *)
// 子对象事件,可以重载这个函数,实现子对象的事件(当获得或者失去子对象的时候)触发
void QObject::childEvent(QChildEvent * /* event */)
// 用于自定义事件的类型
void QObject::customEvent(QEvent * /* event */)
例子:
class CustomEvent : public QEvent
{
public:
CustomEvent() : QEvent(QEvent::User) {}
~CustomEvent() {}
void setData(const QString &data) { m_data = data; }
QString data() const { return m_data; }
private:
QString m_data;
};
class CustomObject : public QObject
{
public:
CustomObject(QObject *parent = 0) : QObject(parent) {}
protected:
void customEvent(QEvent *event) {
if (event->type() == QEvent::User) {
CustomEvent *customEvent = static_cast<CustomEvent*>(event);
qDebug() << "Custom data: " << customEvent->data();
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
CustomObject object;
CustomEvent *customEvent = new CustomEvent();
customEvent->setData("Hello, world!");
QCoreApplication::postEvent(&object, customEvent);
return app.exec();
}
//QObject的事件过滤器。它允许我们在事件分发给接收者之前进行拦截与过滤。对象需要注册才能进行过滤
bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */)
//可以禁止或解除对象的信号发射,返回修改前的状态,方便再设置回来
bool QObject::blockSignals(bool block)
//thread()函数返回对象当前所在的线程
QThread *QObject::thread() const
//将一个QObject对象移动到指定的目标线程中。被移动的对象会脱离当前线程,转移到目标线程。
void QObject::moveToThread(QThread *targetThread)
//对象和子对象都发射 线程变更事件,递归调用子对象
void QObjectPrivate::moveToThread_helper()
//将调用者从 currentData 移动到 targetData
//移动事件函数
void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData)
//重新注册定时器, 再线程切换事件处理中调用
void QObjectPrivate::_q_reregisterTimers(void *pointer)
//启动一个定时器,返回线程id
int QObject::startTimer(int interval)
//杀死一个指定id 的定时器
void QObject::killTimer(int id)
// 查找父对象的子对象,子对象存在list
void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QRegExp *re,
const QMetaObject &mo, QList<void*> *list)
{
if (!parent || !list)
return;
const QObjectList &children = parent->children();
QObject *obj;
for (int i = 0; i < children.size(); ++i) {
obj = children.at(i);
if (mo.cast(obj)) {
if (re) {
if (re->indexIn(obj->objectName()) != -1)
list->append(obj);
} else {
if (name.isNull() || obj->objectName() == name)
list->append(obj);
}
}
qt_qFindChildren_helper(obj, name, re, mo, list);
}
}
//在指定的父对象及其所有子对象中查找特定名称和元对象的第一个子对象。
QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo)
{
if (!parent)
return 0;
const QObjectList &children = parent->children();
QObject *obj;
int i;
for (i = 0; i < children.size(); ++i) {
obj = children.at(i);
if (mo.cast(obj) && (name.isNull() || obj->objectName() == name))
return obj;
}
for (i = 0; i < children.size(); ++i) {
obj = qt_qFindChild_helper(children.at(i), name, mo);
if (obj)
return obj;
}
return 0;
}
//设置父对象
void QObject::setParent(QObject *parent)
//删除对象的所有子对象
void QObjectPrivate::deleteChildren()
//设置对象的父对象
void QObjectPrivate::setParent_helper(QObject *o)
//将对象注册到事件队列中
void QObject::installEventFilter(QObject *obj)
//将对象从队列中移除
void QObject::removeEventFilter(QObject *obj)
//将对象的删除操作放在下一次迭代中,发送消亡事件给coreApplication。
//这使得其他对象有机会在对象实际被删除前与其交互,对象在接下来的事件循环迭代中才真正无效。
void QObject::deleteLater()
// 标记最近函数使用的入口
const char *qFlagLocation(const char *method)
{
static int idx = 0;
flagged_locations[idx] = method;
idx = (idx+1) % flagged_locations_count;
return method;
}
// 用于从方法或信号名称中提取其代码
// 1. 方法或信号名称的首字符为其类型代码
// 2. QMETHOD_CODE = 0,代表普通方法
// 3. QSLOT_CODE = 1,代表槽方法
// 4. QSIGNAL_CODE = 2,代表信号
static int extract_code(const char *member)
{
// extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE
return (((int)(*member) - '0') & 0x3);
}
//用于从方法或信号名称中提取其所属位置信息
static const char * extract_location(const char *member)
{
for (int i = 0; i < flagged_locations_count; ++i) {
if (member == flagged_locations[i]) {
// signature includes location information after the first null-terminator
const char *location = member + qstrlen(member) + 1;
if (*location != '\0')
return location;
return 0;
}
}
return 0;
}
//检查信号是否使用了正确的宏定义,并输出相应的警告信息。
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;
}
//用于检查给定的方法是否使用了正确的宏(SLOT或SIGNAL宏)
static bool check_method_code(int code, const QObject *object,
const char *method, const char *func)
{
if (code != QSLOT_CODE && code != QSIGNAL_CODE) {
qWarning("Object::%s: Use the SLOT or SIGNAL macro to "
"%s %s::%s", func, func, object->metaObject()->className(), method);
return false;
}
return true;
}
//用于在对象中查找指定的方法或槽或信号,并在找不到时打印错误信息
static void err_method_notfound(const QObject *object,
const char *method, const char *func)
{
const char *type = "method";
switch (extract_code(method)) {
case QSLOT_CODE: type = "slot"; break;
case QSIGNAL_CODE: type = "signal"; break;
}
const char *loc = extract_location(method);
if (strchr(method,')') == 0) // common typing mistake
qWarning("Object::%s: Parentheses expected, %s %s::%s%s%s",
func, type, object->metaObject()->className(), method+1,
loc ? " in ":"\0", loc ? loc : "\0");
else
qWarning("Object::%s: No such %s %s::%s%s%s",
func, type, object->metaObject()->className(), method+1,
loc ? " in ":"\0", loc ? loc : "\0");
}
//输出关于QObject信号和槽连接中参与者的信息,主要是发送者和接收者对象的名称。
static void err_info_about_objects(const char * func,
const QObject * sender,
const QObject * receiver)
{
QString a = sender ? sender->objectName() : QString();
QString b = receiver ? receiver->objectName() : QString();
if (!a.isEmpty())
qWarning("Object::%s: (sender name: '%s')", func, a.toLocal8Bit().data());
if (!b.isEmpty())
qWarning("Object::%s: (receiver name: '%s')", func, b.toLocal8Bit().data());
}
//获取当前信号的发送者
QObject *QObject::sender() const
// 找到指定信号的接收槽个数
int QObject::receivers(const char *signal) const
//信号槽连接函数
bool QObject::connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *method,
Qt::ConnectionType type)
//信号槽断开函数
bool QObject::disconnect(const QObject *sender, const char *signal,
const QObject *receiver, const char *method)
//连接事件,虚接口(保护函数)需要 继承于QObject 才能实现
void QObject::connectNotify(const char *signalname)
//断开事件,虚接口(保护函数)需要 继承于QObject 才能实现
void QObject::disconnectNotify(const char *signalname)
//建立QObject 之间的信号和槽连接。信号槽的底层连接
bool QMetaObject::connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index, int type, int *types)
//断开元对象之间的信号和槽连接,遍历sender 的信号连接队列,减少使用。
bool QMetaObject::disconnect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index)
//对象连接子对象信号的槽的实现方式,如界面中控件按下,等这些信号槽的连接
void QMetaObject::connectSlotsByName(QObject *o)
//激活已排队的连接。从发送方中获取接收方信息和信号内容,构造参数列表,发送调用事件到接收方事件中,事件将在事件循环中激活,
static void queued_activate(QObject *sender, int signal, const QObjectPrivate::Connection &c,
void **argv, QSemaphore *semaphore = 0)
//激活阻塞连接
//线程同步机制,发送者线程阻塞,等待接收者线程处理事件后唤醒,保证了串行化的执行。
static void blocking_activate(QObject *sender, int signal, const QObjectPrivate::Connection &c, void **argv)
//信号的激活与派发,调用前面两个函数进行信号的发送
void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv)
//直连信号的发送
void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
void **argv)
void QMetaObject::activate(QObject *sender, const QMetaObject *m,
int from_local_signal_index, int to_local_signal_index, void **argv)
//增加对象的元属性
bool QObject::setProperty(const char *name, const QVariant &value)
//获取对象的原属性
QVariant QObject::property(const char *name) const
//获取对象的动态属性表 ExtraData 列表
QList<QByteArray> QObject::dynamicPropertyNames() const
//设置用户数据, 主要是 ExtraData 类型
void QObject::setUserData(uint id, QObjectUserData* data)
//获取 用户数据标签:const,Qt,int,void,QObject,对象,源码,return,Qobject From: https://www.cnblogs.com/wish-sleeping/p/17399190.html
QObjectUserData* QObject::userData(uint id) const