构造时如果传入的parent,与当前对象不在同一线程则parent无效,其parent将会变成nullptr。
新建的时候如果传入parent则不需要手动delete。
我们在使用QObject过程中,你们有没有发现没有过传值的情况为什么呢?
因为QObject类声明了Q_DISABLE_COPY,所以QObject和其子类都无法传参或赋值,只能使用的指针或引用进行传递。(究其原因就是其复制过程涉及多线程安全和元对象处理起来较复杂)
class Q_CORE_EXPORT QObject
{
Q_OBJECT
public:
explicit QObject(QObject *parent=nullptr);
protected:
QObject(QObjectPrivate &dd, QObject *parent = nullptr);
private:
Q_DISABLE_COPY(QObject)
/* 此宏等同于,删除了拷贝和赋值函数,导致无法进行值传递
QObject(const QObject &) = delete;
QObject &operator=(const QObject &) = delete;
*/
}
#define Q_DISABLE_COPY(Class) \
Class(const Class &) = delete;\
Class &operator=(const Class &) = delete;
QObject::QObject(QObject *parent)
{
QObject(*new QObjectPrivate, parent)
}
QObject::QObject(QObjectPrivate &dd, QObject *parent): d_ptr(&dd)
{
if (parent) {
//如果父子对象不在同一线程则不能有父子关系,此时parent将被设置为nullptr
if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() : nullptr, threadData))
parent = nullptr;
if (d->isWidget) { //Qwidget类型的走这个分支
if (parent) {
d->parent = parent;
d->parent->d_func()->children.append(this);
}
} else {
setParent(parent);//设置parent
}
}
}
设置parent的对象后就不需要我们自己取管理其生命周期,即不需要手动delete,
因为其父对象析构时会自动析构并delete所有子对象。我们只需管理parent生命周期即可
析构时会:
QObject::~QObject()
{
d->wasDeleted = true;
d->blockSig = 0; // unblock signals so we always emit destroyed()
if (!d->isWidget && d->isSignalConnected(0)) {
emit destroyed(this);//发送destroyed信号
}
// 取消所有信号关联的接收者
for (int signal = -1; signal < receiverCount; ++signal)
cd->removeConnection(c);
// 取消所有的槽关联的发送者
while (QObjectPrivate::Connection *node = cd->senders)
senderData->removeConnection(node);
deleteChildren();//析构并删除子对象
if (d->parent)
d->setParent_helper(nullptr);//设置nullptr会先从父对象移除,再设置parent为nullptr
}
void QObjectPrivate::deleteChildren()
{
Q_ASSERT_X(!isDeletingChildren, "QObjectPrivate::deleteChildren()", "isDeletingChildren already set, did this function recurse?");
isDeletingChildren = true;
//遍历删除子对象
for (int i = 0; i < children.count(); ++i) {
currentChildBeingDeleted = children.at(i);
children[i] = 0;
delete currentChildBeingDeleted;
}
children.clear();
currentChildBeingDeleted = nullptr;
isDeletingChildren = false;
}
此函数设置对象的parent,父子对象必须在同一个线程里面才能设置成功。
流程:
取消QObject的父对象,直接设置其parent为nullptr即可,setParent(nullptr);
#QObject的isWidget为false
QObjectPrivate::QObjectPrivate(int version)
: threadData(nullptr), currentChildBeingDeleted(nullptr)
{
wasDeleted = false; // double-delete catcher
......
}
void QObject::setParent(QObject *parent)
{
Q_D(QObject);
//isWidget为true时不应该走到QObject的setParent,应该走QWidget的setParent
Q_ASSERT(!d->isWidget);
d->setParent_helper(parent);
}
void QObjectPrivate::setParent_helper(QObject *new_parent)
{
if (new_parent == parent)//如果设置的父亲与当前父亲相同直接返回
return;
//从当前父对象移除
QObjectPrivate *parentD = parent->d_func();
const int index = parentD->children.indexOf(q);
parentD->children.removeAt(index);
QChildEvent e(QEvent::ChildRemoved, q);
QCoreApplication::sendEvent(parent, &e);//发送移除孩子事件给老父亲
//检查是否同一线程
parent = new_parent;//new_parent设置nullptr,将没有父对象
if (threadData != parent->d_func()->threadData)
{
//如果新的父亲对象和当前对象不在同一线程无法设置成功。
//注意此时的对象没有父亲了已经,其声明周期需要自己管理
parent = nullptr;
return;
}
//添加到新父亲里面
if(parent){
parent->d_func()->children.append(q);
QChildEvent e(QEvent::ChildAdded, q);
QCoreApplication::sendEvent(parent, &e);//发送添加孩子事件给新父亲
}
}
#QWidget的isWidget为true
QWidgetPrivate::QWidgetPrivate(int version)
{
......
isWidget = true;
}
void QWidget::setParent(QWidget *parent)
{
if (parent == parentWidget())//如果设置的父亲与当前父亲相同直接返回
return;
setParent((QWidget*)parent, windowFlags() & ~Qt::WindowType_Mask);
}
QObject *parent() const { return d_ptr->parent; }
此函数用来获取parent,没有父亲则返回nullptr
通过对象名称查找符合条件的所有对象,setObjectName可以设置对象名称
QList<myobject > list = obj1->findChildren<myobject>(“”, Qt::FindChildrenRecursively);//所有对象都不会被查到
QList<myobject > list = obj1->findChildren<myobject>();//所有对象都被查到
QList<myobject > list = obj1->findChildren<myobject>(“obj3”, Qt::FindChildrenRecursively);//查到对象名称为obj3的所有对象
Qt::FindChildrenRecursively表示查找所有子对象和子对象递归,默认值
Qt::FindDirectChildrenOnly表示只查找其直接的子对象,不递归查找
myobject *obj1 = new myobject("boj1");
myobject *obj2= new myobject("boj2");
myobject *obj3= new myobject("boj3");
obj3->setObjectName("obj3");
obj1->setObjectName("obj1");
obj2->setObjectName("obj2");
obj2->setParent(obj1);
obj3->setParent(obj1);
;
QList<myobject *> list = obj1->findChildren<myobject*>("obj3",Qt::FindChildrenRecursively);
if(list.size()>0)
{
qDebug()<<list;
}
QList<myobject *> list2 = obj1->findChildren<myobject*>(QRegExp("(obj\\d+)"),Qt::FindChildrenRecursively);
if(list.size()>0)
{
qDebug()<<list2;
}
myobject *chird = obj1->findChild<myobject*>("obj3",Qt::FindChildrenRecursively);
if(chird)
{
qDebug()<<chird;
}
const QObjectList &children() const
返回所有子对象列表
通过对象名称查找符合条件的第一个对象,仅返回一个对象
模板函数
template<typename T>
inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
{
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
return static_cast<T>(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));
}
myobject *chird = obj1->findChild<myobject*>("obj3",Qt::FindChildrenRecursively);
if(chird)
{
qDebug()<<chird;
}