1、直接删除,释放widget和layout
QLayout* layout;
QLayoutItem *child;
//每次使用takeAt取了之后,原有的count就会减少,所以每次取下标为0的即可
while ((child = layout->takeAt(0)) != NULL)
{
if (child->widget())
{
child->widget()->setParent(NULL);
delete child->widget();
}
else if (child->layout())
{
layout->removeItem(child->layout());
}
delete child;
child = NULL;
}
delete layout;
查了网上的函数用法,发现主要是获取layout下的控件数,并且将其删除,但是这个并没有有效解决清除Widget下的所有子控件的问题,在使用时,仍然发现更深层次的子控件没有删除,反而失去管理了。所以这个方法只适用于没有更深子控件的情况。
2、介绍一下ItemAt,takeAt,Count这三个函数
Count这个函数是返回layout下的本层次的控件数量,例如设置了一个两层的布局,外层的GridLayout计算count时,只会得出结果2,无论内层的HBoxLayout添加多少个,都和外层的无关。
QGridLayout* GLayout = new QGridLayout(this);
QHBoxLayout* HLayout = new QHBoxLayout(this);
QWidget* wid = new QWidget();
QWidget* wid2 = new QWidget();
HLayout->addWidget(wid2, 0, 0);
GLayout->addWidget(wid, 0, 0);
GLayout->addLayout(HLayout, 1, 0);
//实际的结果为2, count这里只计算了wid和HLayout,
//而更深层次的wid2,则是作为HLayout的子控件,没有被计算进来
int count = layout->layout()->count();
同理ItemAt这个函数是根据当前布局的下标去拷贝一份控件出来,也是仅仅拷贝的这一层次,无法直接拷贝更深层次的控件;takeAt则是直接剪切,原有的count会直接减少一份。
所以想要彻底的删除所有控件,肯定是需要递归判断的
3、递归移除/删除效果实现
这里使用了函数模板来包装lambda函数的方式来实现。
首先获取layout下的控件数量,再判断其是否为widget,或者为layout,widget可以直接删除,而layout则需要继续递归检查
std::function<void(QLayout *layout)> func_clear = [&](QLayout *layout)
{
int count = layout->layout()->count();
for(int j = 0; j < count; j++)
{
QLayoutItem *item = layout->layout()->itemAt(0);
QWidget *wid = item->widget();
QLayout *layoutItem = item->layout();
if(wid)
{
layout->removeWidget(wid);//先移除控件
//wid->setHidden(true);//再设置不可见
delete wid;
}
if(layoutItem)
{
func_clear(layoutItem);//递归检查layout下的子控件情况
layout->removeItem(layoutItem);
delete layoutItem;
}
}
};
func_clear(m_GLayout);
4、回收widget,只删除layout
对于某些情况下,widget上保存的数据比较宝贵(时间戳,或者其他获取麻烦,耗时长的数据),还需要暂时的将widget回收起来,在下一步或者后续的界面绘制中再次使用。
所以这个时候,就是将widget只是从父窗口中移除,而非删除,这里调用的方法则是removeWidget和setHidden(true)。其中removeWidget只是移除在layout布局上的逻辑关系,而从UI界面去除,则是需要调用setHidden将窗口隐藏起来。
layout->removeWidget(wid);//先移除控件
wid->setHidden(true);//再设置不可见
//delete wid;
5、清除后再次添加,方便重新布局
我们清除的时候,建议清除到widget这一层级结束,然后向正常情况一样,从头给控件添加布局
delete GLayout;
GLayout = new QGridLayout(this);
如果只是清除layout,则可能会导致原有的布局不正确,建议还是重新添加一个GridLayout;
5、遇到窗口布局不正确的排查思路
5.1、优先检查是否没有清除完,当执行完删除后,不妨再次获取一下count数量,看下是否还有其他的子控件
5.2、注意是否是递归遍历
5.3、如果没有正确删除,只是调用了removeWidget,则可能会导致运行中内存泄漏
6、对于widget控件,使用findChildren来查找子控件
//注意是使用widget去查找,而非layout,这里是查找widget下是否有T类型的子控件
QList<T> list = widget->findChildren<T>();
//上面的查找默认是递归的,也可以添加参数只查找当下这一层
QList<T> list = widget->findChildren<T>(QString(), Qt::FindDirectChildrenOnly);
//并且还可以直接根据objName进行定向查找到控件
QList<QWidget *> widgets = widget.findChildren<QWidget *>("widgetname");
版权归原作者 C++筑基期 所有, 如有侵权,请联系我们删除。