删除布局会删除其子布局吗?

Does deleting layout deletes its sublayouts?

我正在开发 Qt 应用程序。我在那里创建布局并添加子布局。 我已经看到调用 addLayout() 将容器布局设置为父级。 这是否意味着当我删除 superlayout 时,它的后代也会被删除?

QWidget* centralWidget = new QWidget(this);
QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
QFormLayout *formLayout = new QFormLayout;
mainLayout->addLayout(formLayout);

删除centralWidget会删除formLayout吗? 感谢和问候

关于生命周期管理(或者换句话说:删除什么),Qt doc中有一个额外的章节。:

Object Trees & Ownership

QObjects organize themselves in object trees. When you create a QObject with another object as parent, it's added to the parent's children() list, and is deleted when the parent is. It turns out that this approach fits the needs of GUI objects very well. For example, a QShortcut (keyboard shortcut) is a child of the relevant window, so when the user closes that window, the shortcut is deleted too.

...

QWidget, the fundamental class of the Qt Widgets module, extends the parent-child relationship. A child normally also becomes a child widget, i.e. it is displayed in its parent's coordinate system and is graphically clipped by its parent's boundaries. For example, when the application deletes a message box after it has been closed, the message box's buttons and label are also deleted, just as we'd want, because the buttons and label are children of the message box.

You can also delete child objects yourself, and they will remove themselves from their parents. For example, when the user removes a toolbar it may lead to the application deleting one of its QToolBar objects, in which case the tool bar's QMainWindow parent would detect the change and reconfigure its screen space accordingly.

The debugging functions QObject::dumpObjectTree() and QObject::dumpObjectInfo() are often useful when an application looks or acts strangely.

正在寻找文档。 QVBoxLayout::addLayout(),我来到了:

void QBoxLayout::addLayout(QLayout *layout, int stretch = 0)

Adds layout to the end of the box, with serial stretch factor stretch.

See also insertLayout(), addItem(), and addWidget().

这不是很有帮助,但在 link 之后,我最终进入了

void QLayout::addItem(QLayoutItem *item)

Implemented in subclasses to add an item. How it is added is specific to each subclass.

This function is not usually called in application code. To add a widget to a layout, use the addWidget() function; to add a child layout, use the addLayout() function provided by the relevant QLayout subclass.

Note: The ownership of item is transferred to the layout, and it's the layout's responsibility to delete it.

项目的所有权转移到布局,布局负责删除它。

为了说明这一点,我做了一个小样本testQLayoutDelete.cc,类似于OP的公开代码:

#include <QtWidgets>

#define DEBUG_DELETE(CLASS) \
struct CLASS: Q##CLASS { \
  CLASS(QWidget *pQParent = nullptr): Q##CLASS(pQParent) { } \
  virtual ~CLASS() { qDebug() << #CLASS"::~"#CLASS"();"; } \
}

DEBUG_DELETE(Widget);
DEBUG_DELETE(VBoxLayout);
DEBUG_DELETE(FormLayout);
DEBUG_DELETE(PushButton);

int main(int argc, char *argv[])
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // setup UI
  QWidget *pQCentralWidget = new Widget();
  QVBoxLayout *pQMainLayout = new VBoxLayout(pQCentralWidget);
  QFormLayout *pQFormLayout = new FormLayout;
  QPushButton *pQButton = new PushButton();
  pQFormLayout->addRow(QString("The button: "), pQButton);
  pQMainLayout->addLayout(pQFormLayout);
  pQCentralWidget->show();
  // enter runtime loop
  int ret = app.exec();
  // clean up explicitly (for illustration of recursive destruction)
  qDebug() << "delete pQCentralWidget;";
  delete pQCentralWidget;
  // done
  qDebug() << "return ret;";
  return ret;
}

我做了一个小帮助宏 DEBUG_DELETE() 来派生每个涉及的 Qt widget/layout class,其中重载的析构函数会产生相应的调试输出。

一个Qt工程文件testQLayoutDelete.pro编译它:

SOURCES = testQLayoutDelete.cc

QT += widgets

在 Windows 10 的 cygwin64 中编译和测试:

$ qmake-qt5 testQLayoutDelete.pro

$ make && ./testQLayoutDelete
Qt Version: 5.9.4

点击×按钮后,出现有趣的输出:

delete pQCentralWidget;
Widget::~Widget();
VBoxLayout::~VBoxLayout();
FormLayout::~FormLayout();
PushButton::~PushButton();
return ret;

$