Qt - 从布局中删除所有小部件?

60 c++ mobile qt nokia qt4

这似乎并不容易.基本上,我通过函数将QPushButtons添加到布局中,当函数执行时,我想首先清除布局(删除所有QPushButtons以及其中的任何其他内容),因为更多按钮只会附加到滚动视图.

QVBoxLayout* _layout;
Run Code Online (Sandbox Code Playgroud)

CPP

void MainWindow::removeButtonsThenAddMore(const QString &item) {

//remove buttons/widgets

QVBoxLayout* _layout = new QVBoxLayout(this);

QPushButton button = new QPushButton(item);
_layout->addWidget(button);

QPushButton button = new QPushButton("button");
_layout->addWidget(button);

QWidget* widget = new QWidget();
widget->setLayout(_layout);

QScrollArea* scroll = new QScrollArea();
scroll->setWidget(widget);
scroll->show();

}
Run Code Online (Sandbox Code Playgroud)

Tee*_*sti 42

我有同样的问题:我有一个游戏应用程序,其主窗口类继承QMainWindow.它的构造函数看起来部分如下:

m_scene = new QGraphicsScene;
m_scene->setBackgroundBrush( Qt::black );
...
m_view = new QGraphicsView( m_scene );
...
setCentralWidget( m_view );
Run Code Online (Sandbox Code Playgroud)

当我想显示游戏关卡时,我实例化一个QGridLayout,我在其中添加QLabel,然后将它们的像素图设置为某些图片(带有透明部分的pixmaps).第一级显示正常,但是当切换到第二级时,第一级的像素图仍然可以在新的像素图后面看到(像素图是透明的).

我尝试了几件事来删除旧的小部件.(a)我尝试删除QGridLayout并实例化一个新的,但后来了解到删除布局不会删除添加到它的小部件.(b)我尝试在新的pixmaps上调用QLabel :: clear(),但这当然只会影响新的像素,而不会影响僵尸.(c)我甚至尝试删除我的m_view和m_scene,并在每次显示新级别时重建它们,但仍然没有运气.

然后(d)我尝试了上面给出的解决方案之一,即

QLayoutItem *wItem;
while (wItem = widget->layout()->takeAt(0) != 0)
    delete wItem;
Run Code Online (Sandbox Code Playgroud)

但这也行不通.

然而,谷歌搜索进一步,我找到了一个有效的答案.(d)遗漏的是打电话给delete item->widget().以下现在对我有用:

// THIS IS THE SOLUTION!
// Delete all existing widgets, if any.
if ( m_view->layout() != NULL )
{
    QLayoutItem* item;
    while ( ( item = m_view->layout()->takeAt( 0 ) ) != NULL )
    {
        delete item->widget();
        delete item;
    }
    delete m_view->layout();
}
Run Code Online (Sandbox Code Playgroud)

然后我像第一级一样实例化一个新的QGridLayout,向它添加新级别的小部件,等等.

Qt在很多方面都很棒,但我认为这些问题表明这里的事情可能会更容易一些.


Dar*_*vic 38

Qt帮助中的布局管理页面说明:

布局将自动重新显示窗口小部件(使用QWidget :: setParent()),以便它们是安装布局的窗口小部件的子窗口.

我的结论:小部件需要手动销毁或通过销毁父WIDGET而不是布局来销毁

布局中的窗口小部件是安装布局的窗口小部件的子窗口,而不是布局本身.窗口小部件只能将其他窗口小部件作为父窗口,而不是布局.

我的结论:同上

致@Muelner的"矛盾""项目的所有权转移到布局,布局的责任是删除它." - 这并不意味着WIDGET,而是重新布局的ITEM,稍后将被布局删除.窗口小部件仍然是安装布局的窗口小部件的子窗口,需要手动删除它们或删除整个父窗口小部件.

如果一个人真的需要从布局中删除所有小部件和项目,让它完全为空,他需要创建一个递归函数,如下所示:

// shallowly tested, seems to work, but apply the logic

void clearLayout(QLayout* layout, bool deleteWidgets = true)
{
    while (QLayoutItem* item = layout->takeAt(0))
    {
        if (deleteWidgets)
        {
            if (QWidget* widget = item->widget())
                widget->deleteLater();
        }
        if (QLayout* childLayout = item->layout())
            clearLayout(childLayout, deleteWidgets);
        delete item;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果小部件有信号连接到它们,这是危险的,因为在调用clearLayout(...)时可能存在未决事件. (2认同)
  • 为了防止挂起事件的这个问题,可能应该调用widget-> deleteLater()而不是只删除? (2认同)

m.w*_*.w. 12

我知道这个问题很老并且已经回答了,但是:由于QtAlgorithms提供了qDeleteAll,因此可以删除布局,包括使用单行删除所有子代.此代码删除布局,其所有子项以及布局内的所有内容都"消失".

qDeleteAll(yourWidget->children());
Run Code Online (Sandbox Code Playgroud)

以下是重载函数的说明:

void qDeleteAll(ForwardIterator begin,ForwardIterator end)

使用C++ delete>运算符删除[begin,end]范围内的所有项目.项类型必须是指针类型(例如,QWidget*).

请注意,qDeleteAll需要从该窗口小部件(而不是该布局)提供容器.请注意,qDeleteAll不会删除QtAlgorithms- 只是它的子项.

现在可以设置新的布局.


hmu*_*ner 8

未尝试:为什么不创建新布局,将其与旧布局交换并删除旧布局?这应该删除布局所拥有的所有项目并保留其他项目.

编辑:在研究了我的答案,文档和Qt源代码的评论后,我发现了一个更好的解决方案:

如果你仍然启用了Qt3支持,你可以使用QLayout :: deleteAllItems(),这与QLayout :: takeAt的文档中的提示基本相同:

以下代码片段显示了从布局中删除所有项目的安全方法:

QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
  ...
  delete child;
}
Run Code Online (Sandbox Code Playgroud)

编辑:经过进一步的研究,看起来上面的两个版本都是等价的:只有子布局和没有父项的小部件被删除.父母的小部件以特殊方式处理.看起来TeL的解决方案应该可行,您应该注意不要删除任何顶级小部件.另一种方法是使用窗口小部件层次结构删除窗口小部件:创建一个没有父窗口的特殊窗口小部件,并创建所有可移动窗口小部件作为此特殊窗口小部件的子窗口.清理布局后删除此特殊小部件.

  • 这不会删除布局中已存在的窗口小部件,因为窗口小部件属于父窗口小部件,而不是布局. (3认同)

Liz*_*Liz 5

您还需要确保删除间隔器和不是 QWidget 的东西。如果您确定布局中唯一的东西是 QWidgets,那么前面的答案就可以了。否则你应该这样做:

QLayoutItem *wItem;
while (wItem = widget->layout()->takeAt(0) != 0)
      delete wItem;
Run Code Online (Sandbox Code Playgroud)

了解如何执行此操作很重要,因为如果您要清除的布局是更大布局的一部分,则您不想破坏该布局。您希望确保您的布局保持其位置以及与窗口其余部分的关系。

您还应该小心,每次调用此方法时都会创建大量对象,并且不会清除它们。首先,您可能应该在其他地方创建 QWidget 和 QScrollArea,并保留一个指向它们的成员变量以供参考。那么您的代码可能如下所示:

QLayout *_layout = WidgetMemberVariable->layout();

// If it is the first time and the layout has not been created
if (_layout == 0)
{
  _layout = new QVBoxLayout(this);
  WidgetMemberVariable->setLayout(_layout);
}

// Delete all the existing buttons in the layout
QLayoutItem *wItem;
while (wItem = widget->layout()->takeAt(0) != 0)
    delete wItem;

//  Add your new buttons here.
QPushButton button = new QPushButton(item);
_layout->addWidget(button);

QPushButton button = new QPushButton("button");
_layout->addWidget(button);
Run Code Online (Sandbox Code Playgroud)


Bas*_*Ben 0

如果你想删除所有小部件,你可以这样做:

foreach (QObject *object, _layout->children()) {
  QWidget *widget = qobject_cast<QWidget*>(object);
  if (widget) {
    delete widget;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • QLayout 不能是 QWidget 的父级。所以 qLayout-&gt;childern() 返回 0 个项目。 (2认同)