关于在Qt 4中删除、移除小部件和布局

23

我使用Qt 4.7,Windows 7,64位。

我创建了一个自定义表格。每一行都是一个带有小部件的水平布局。将这些行保存在QList中,以便轻松访问其中的子项。这些行也被添加到父窗口中。

如果我调整父窗口的大小,我会计算新的大小,删除所有内容,然后再重新创建。

我的问题是我不想删除任何小部件。只有在清除表格时才执行此操作。

由于我已经将小部件放置在QList和父母布局中,那么如何删除每一行中的所有小部件、删除所有布局,然后将它们添加到新布局中呢?

如果我对每个布局中的每个元素执行takeAt(0),我会得到一个包含小部件的QLayoutItem...如何删除QLayoutItem而不删除小部件呢?...如何删除小部件而不摧毁它,无论它是在父级还是在子级中?因为在布局中有许多删除方法:removeItem、removeWidget...但没有takeWidget...只有takeAt()它会返回一个Qlayoutitem。

我尝试了几种方法,但无论发生什么,我仍然可以看到小部件。

关于此的问题:

  • 小部件何时被删除?如果我从布局中取出takeWidget(index),它是否会自动删除?如果在另一个列表中有它的指针,会发生什么?

  • removeAt(index)方法执行小部件的delete方法吗?

2个回答

33

好的,我搞定了。让我解释一下这个“移除、保留小部件”的工作原理。

一个小部件是通过其父布局来确定的。你可以通过布局来移除它。具体操作如下:

layout()->removeAt(widget);
delete widget;

如果您在QLayout(或其子类)中使用takeAt(index),它将给您一个QLayoutItem。要访问其中的小部件,请使用widget()。但是没有办法在不删除小部件的情况下删除它。因此,这种方法是无效的。

文档中介绍了一种删除元素的方法:

QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0)  {
    ...
    delete child;
}
在Qt中需要特别注意以下事项: 如果您有一棵布局层次树,其中包含使用addLayout()在布局内添加的子布局,则无论您的窗口小部件插入到多深的位置,只要该树路径是由子布局构建而成的,就可以从子布局或任何父布局中删除它。
最简单的方法是在自定义表中保留所有项目的指针列表。当清除表以重构时,只需在窗口小部件内执行以下操作:
  CustomTableItem* item;
  while ( !items_.isEmpty() && ( (item = items_.takeFirst()) != 0 ) ){
    layout()->removeWidget(item);
    delete item; // It works no matter where the item is
  }

  items_.clear(); // clear the list afterwards.

它完美地工作,并且能够自动更新布局。 如果你想保留元素,只需跳过“delete item;”,然后在之后使用它们。

需要注意的重要事项是,在QList或类似小部件中,不同的“remove”函数具有不同的作用(就我所知,在Qt文档中),以及在QLayout中。

在 QList 中,removeAt 实际上会删除对象。

(Qt 4.7 QList 文档) "删除索引位置 i 处的项目。i 必须是列表中的有效索引位置(即 0 <= i < size())。"

在 QLayout 中,removeWidget 或 removeItem 不会删除该项/小部件,您需要负责将其删除,就像我之前所做的那样。

(Qt 4.7 QLayout 文档) "从布局中删除 widget 小部件。调用此函数后,调用者有责任赋予小部件合理的几何属性,或将其放回布局中。"

希望这有所帮助。如果您发现任何错误,可以告诉我,我会编辑答案!

更多关于删除内容的信息: 其他 stackoverflow 帖子


1
layout()->removeAt(widget); 仅适用于 QGraphicsLayout。你可能想要使用的是 layout()->removeWidget(widget);。 - Bim
1
这也是您可以执行的操作,以从布局中删除小部件而不删除它。如果您没有小部件指针,请执行以下操作:QLayoutItem * item = layout->itemAt(0); QWidget * widget = item->widget(); if (widget != NULL) { layout->removeWidget(widget); //如果您想删除小部件,请执行: widget->setParent(NULL); delete widget; }(格式可能无法正常显示,但您已经了解了意思...) - Bim
请注意,这在Python中无效,因为您还必须处理内部的C++对象。 - Darkgaze
1
当需要从事件处理程序(槽)中销毁该项时,必须调用item->deleteLater(),如“其他帖子”所示。否则将发生堆破坏。 - MiB_Coder

8

在Qt中,小部件是一个常规的C++对象,可以像其他对象一样使用C++ delete运算符进行删除:

delete myWidget;

在Qt中,小部件之间总是存在父子关系。当父小部件被销毁时,它将删除所有子小部件。通常情况下,您不需要考虑显式删除任何小部件,但顶级小部件,即窗口和对话框,需要注意。Qt会负责删除任何子小部件。
QList :: removeAt(int)不会删除被移除的对象,它只会从列表中删除该对象。如果您还想删除该对象,则需要执行类似以下操作:
delete myList.takeAt(0);

这适用于所有函数,例如 removeAt(int)takeAt(int)takeFirst() 等等。它们从容器(列表、布局、滚动区域等)中移除对象,但不会删除它们。在大多数情况下,小部件的所有权随后转移到调用方(调用方成为负责删除小部件的父级,因为父子关系断开),但不要假设这总是发生,始终阅读函数的文档。


1
谢谢!但是我的问题怎么办:我有一个QBoxLayout。我使用takeAt(int)来获取元素。它不是一个小部件,而是一个QLayoutItem。要获取小部件,我使用widget(void)函数。但是小部件仍然在里面。如何取出小部件并删除该LayoutItem?没有这样的功能! - Darkgaze
请注意,这在Python中无效。您还需要注意内部的C++对象。 - Darkgaze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接