QObject_parent

QObject

构造

构造时如果传入的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生命周期即可

析构时会:

  1. 自动销毁children,并且从父对象中移除它
  2. 析构自动解除所有信号和槽的连接关系
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;
}

void QObject::setParent(QObject *parent);

此函数设置对象的parent,父子对象必须在同一个线程里面才能设置成功。
流程:

  1. 先从当前父对象移除,并且触发老的父对象QEvent::ChildRemoved
  2. 检查新父对象与当前对象是否同一线程,不在的话直接返回(此时的对象已经没有父亲,其生命周期需要自己管理 )
  3. 在同一线程则添加到新父亲里面,添加成功后触发新父对象QEvent::ChildAdded的事件

取消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);
}

获取parent

QObject *parent() const { return d_ptr->parent; }
此函数用来获取parent,没有父亲则返回nullptr

findChildren

通过对象名称查找符合条件的所有对象,setObjectName可以设置对象名称
QList> list = obj1->findChildren>(“”, Qt::FindChildrenRecursively);//所有对象都不会被查到
QList> list = obj1->findChildren>();//所有对象都被查到
QList> list = obj1->findChildren>(“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  list = obj1->findChildren("obj3",Qt::FindChildrenRecursively);
    if(list.size()>0)
    {
         qDebug()<  list2 = obj1->findChildren(QRegExp("(obj\\d+)"),Qt::FindChildrenRecursively);
    if(list.size()>0)
    {
         qDebug()<findChild("obj3",Qt::FindChildrenRecursively);
    if(chird)
    {
         qDebug()<

children

const QObjectList &children() const
返回所有子对象列表

findChild

通过对象名称查找符合条件的第一个对象,仅返回一个对象

模板函数
    template
    inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
    {
        typedef typename std::remove_cv::type>::type ObjType;
        return static_cast(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));
    }  

 myobject *chird = obj1->findChild("obj3",Qt::FindChildrenRecursively);
    if(chird)
    {
         qDebug()<

你可能感兴趣的:(qt,qt)