Qt 调用setLayout后,父对象自动设置

发布于:2025-09-15 ⋅ 阅读:(21) ⋅ 点赞:(0)

1、先来看一个简单的Qt程序,代码如下:

LabelEx.h 

#ifndef LABELEX_H
#define LABELEX_H

#include <qlabel.h>

// 简单重写QLabel类
class LabelEx : public QLabel
{
    Q_OBJECT
public:
    explicit LabelEx(QWidget *parent = nullptr);
    ~LabelEx();
    
signals:
};

#endif // LABELEX_H

LabelEx.cpp

#include "LabelEx.h"
#include <qdebug.h>

LabelEx::LabelEx(QWidget *parent)
    : QLabel{parent}
{}

LabelEx::~LabelEx()
{
    qDebug() << "LabelEx destructor";
}

测试对话框:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include "LabelEx.h"

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();
    
private:
    void init();
    
private:
    LabelEx *m_lbInfo = nullptr;
};
#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include <qboxlayout.h>
#include <qdebug.h>

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    init();
}

Dialog::~Dialog() {}

void Dialog::init()
{
    setMinimumSize(200, 200);
    
    m_lbInfo = new LabelEx();        // 无父对象
    m_lbInfo->setText("测试1");
    
    QHBoxLayout *hLay = new QHBoxLayout();    // 无父对象
    hLay->addWidget(m_lbInfo);
    
    if (m_lbInfo->parent() == hLay) {
        qDebug() << "m_lbInfo->parent() == hLay";
    }
    if (m_lbInfo->parent() == this) {
        qDebug() << "m_lbInfo->parent() == this";
    }
    if (m_lbInfo->parent() == nullptr) {
        qDebug() << "m_lbInfo->parent() == nullptr";
    }
    
    if (hLay->parent() == this) {
        qDebug() << "hLay->parent() == this";
    }
    if (hLay->parent() == nullptr) {
        qDebug() << "hLay->parent() == nullptr";
    }
}

运行后可以看到打印信息:

m_lbInfo->parent() == nullptr
hLay->parent() == nullptr

关闭对话框后,m_lbInfo没有调用析构函数,与hLay都存在内存泄漏的风险(因为没有父对象,不会自动释放资源)

修改Dialog::init()后:

void Dialog::init()
{
    setMinimumSize(200, 200);
    
    m_lbInfo = new LabelEx();        // 无父对象
    m_lbInfo->setText("测试1");
    
    QHBoxLayout *hLay = new QHBoxLayout();        // 无父对象
    hLay->addWidget(m_lbInfo);
    this->setLayout(hLay);
    
    if (m_lbInfo->parent() == hLay) {
        qDebug() << "m_lbInfo->parent() == hLay";
    }
    if (m_lbInfo->parent() == this) {
        qDebug() << "m_lbInfo->parent() == this";
    }
    if (m_lbInfo->parent() == nullptr) {
        qDebug() << "m_lbInfo->parent() == nullptr";
    }
    
    if (hLay->parent() == this) {
        qDebug() << "hLay->parent() == this";
    }
    if (hLay->parent() == nullptr) {
        qDebug() << "hLay->parent() == nullptr";
    }
}

其实只是增加一行代码:this->setLayout(hLay)

可以看出打印信息:

m_lbInfo->parent() == this
hLay->parent() == this

由此可见,QWidget对象在调用setLayout(QLayout *lay)后,会把lay和lay布局中的QWidget对象都设为自身的子对象。

关闭对话框后,打印信息:LabelEx destructor

m_lbInfo调用了析构函数,自动释放了资源。

【题外话】QObject对象在释放资源时,会自动释放它子对象的资源,相信大家都明白,因为QObject有一个QObjectList类型的对象,专门管理子对象,包括释放自身资源前会遍历释放子对象资源。

2、扩展

修改Dialog类

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include "LabelEx.h"

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();
    
private:
    void init();
    
private:
    QWidget *m_wgt = nullptr;
    LabelEx *m_lbInfo = nullptr;
};
#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include <qboxlayout.h>
#include <qdebug.h>

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    init();
}

Dialog::~Dialog() {}

void Dialog::init()
{
    setMinimumSize(600, 200);
    
    m_wgt = new QWidget();              // 无父对象
    m_lbInfo = new LabelEx(m_wgt);      // 父对象为m_wgt
    m_lbInfo->setText("测试1:");
    
    QHBoxLayout *hLay = new QHBoxLayout();
    hLay->addWidget(m_lbInfo);
    m_wgt->setLayout(hLay);
    
    QVBoxLayout *vLay = new QVBoxLayout();
    vLay->addWidget(m_wgt);
    this->setLayout(vLay);
    
    if (m_lbInfo->parent() == m_wgt){
        qDebug() << "m_lbInfo->parent() == m_wgt";
    }
    if (m_lbInfo->parent() == hLay) {
        qDebug() << "m_lbInfo->parent() == hLay";
    }
    if (m_lbInfo->parent() == this) {
        qDebug() << "m_lbInfo->parent() == this";
    }
    
    if (m_wgt->parent() == this) {
        qDebug() << "m_wgt->parent() == this";
    } else {
        qDebug() << "m_wgt->parent() != this";
    }
    
    if (hLay->parent() == m_wgt) {
        qDebug() << "hLay->parent() == m_wgt";
    }
    if (hLay->parent() == this) {
        qDebug() << "hLay->parent() == this";
    }
    
    if (vLay->parent() == this) {
        qDebug() << "vLay->parent() == this";
    } else {
        qDebug() << "vLay->parent() != this";
    }
}

运行程序后,打印信息如下:

m_lbInfo->parent() == m_wgt
m_wgt->parent() == this
hLay->parent() == m_wgt
vLay->parent() == this

【分析】由于m_wgt嵌入在vLay布局中,而vLay的父对象是this,因而m_wgt的父对象也变为this。由于调用了m_wgt->setLayout(hLay),因而hLay的父对象是m_wgt(注意不是this),m_lbInfo嵌入在hLay中,因此它的父对象也随hLay。

退出对话框后,打印信息:LabelEx destructor

m_lbInfo自动释放了资源(它毕竟属于Dialog的孙对象,在m_wgt释放对象前不会忘了它)