0


(QT-UI)一、清除widget下的所有子控件

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");
标签: qt ui c++

本文转载自: https://blog.csdn.net/m0_60558754/article/details/140270535
版权归原作者 C++筑基期 所有, 如有侵权,请联系我们删除。

“(QT-UI)一、清除widget下的所有子控件”的评论:

还没有评论