天天看点

Qt控件在布局内(QFormLayout、QGridLayout等)的动态添加与删除项目场景:问题描述:代码:总结如下:

项目场景:

在项目开发过程中,比如报警信息的显示,如果将所有的报警信息都添加至布局内,再以控件隐藏与显示的方式进行报警,这种方法无疑是最简单的,但是如果报警种类过多,但往往需要显示的很少,在界面里面去一个个拖控件或者代码添加都太麻烦,这就需要动态添加与删除了!

问题描述:

就以下图为例吧:

因为电池电芯不固定,可能是8芯可能是16芯,所以1、2、3部分都是动态更新的。

且都使用了groupbox容器,不同的是1、2放置formlayout布局,3放置gridlayout布局。

Qt控件在布局内(QFormLayout、QGridLayout等)的动态添加与删除项目场景:问题描述:代码:总结如下:

代码:

动态添加

添加代码很简单,按需要添加即可:

void QFormLayout::addRow(const QString &labelText, QWidget *field)

void QGridLayout::addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment = Qt::Alignment())

但是每次添加前必须将布局里面的控件删除,在操作过程中发现极易出错。

动态删除

  • QFormLayout:
  1. 方法一:(推荐)

QFormLayout里面有两个函数

void QFormLayout::removeRow(int row)

//从布局中删除并删除相应的widgets 无内存泄漏危险

QFormLayout::TakeRowResult QFormLayout::takeRow(int row)

//从布局中删除并返回相应的widgets 有内存泄漏危险

我们这里肯定采用removeRow方法了

下面是错误用法

if(ui->formLayout->rowCount())
    {
        for (int i = 0; i <= ui->formLayout->rowCount(); ++i )
        {
            ui->formLayout->removeRow(0);
        }
    }
           

出错原因:ui->formLayout->rowCount()是动态更新的

更正:

int count = ui->formLayout->rowCount();
    if(count)
    {
        for (int i = 0; i <= count; ++i )
        {
            ui->formLayout->removeRow(0);
        }
    }
           

或者

while (ui->formLayout->rowCount())
    {
        ui->formLayout->removeRow(0);
    }
           

或者最后一行开始删除!!!!!

if(ui->formLayout->rowCount())
    {
        for (int i = ui->formLayout->rowCount() - 1; i >= 0; --i )
        {

            ui->formLayout->removeRow(i);
        }
    }
           

ui->formLayout->这可以类比到tablewidget的数据动态更新~

  1. 方法二:

    通过QLayoutItem删除

QLayoutItem* item;
    while((item = ui->formLayout_2->takeAt(0)) != 0)
    {
        if(item->widget())
        {
            ui->formLayout_2->removeWidget(item->widget());
            item->widget()->setParent(0);
            delete item->widget();
        }
    }
           
  1. 方法三:

    通过查找Groupbox容器的子控件进行删除,没错,这是个容易错误的地方,不要查找formLayout布局的子控件,经测试,这样并不会有删除效果(对比QGridLayout方法3呈现的效果不同)。

    原因参考论坛中的解释:

    layout是需要一个QWidget作为容器的,所有加入layout中的控件都是对应容器的子控件,因此从容器中查找子控件,然后删除是最合适的方法。你原来删除的是QLayoutItem,不是QPushButton,所以有内存泄露,也就是说你只是把QPushButton从layout里面移除了,所以它不显示,但是并不代表这个QPushButton被完全删除了

QList<QLabel*> all_labs = ui->groupBox_3->findChildren<QLabel*>();
  QList<QLineEdit*> all_leds = ui->groupBox_3->findChildren<QLineEdit*>();
    for (auto* lab : all_labs)
    {
        delete lab;
    }
    for (auto* led : all_leds)
    {
        delete led;
    }
           
  • QGridLayout:

    QGridLayout不像QFormLayout里有removeRow方法,所以提供两种方法:

    1、通过QLayoutItem删除

QLayoutItem* item;
    while((item = ui->gridLayout->takeAt(0)) != 0)
    {
        if(item->widget())
        {
            ui->gridLayout->removeWidget(item->widget());
            item->widget()->setParent(0);
            delete item->widget();
        }
    }
           

2、 通过查找Groupbox容器的子控件进行删除

QList<QLabel*> all_labs = ui->groupBox->findChildren<QLabel*>();//注意不是gridLayout
    for (auto* lab : all_labs)    
    {
       delete lab;
    }
           

如果查找formLayout布局的子控件删除,则只会有删除效果(这与上面的QFormLayout呈现效果不同),但是并没有真正的删除,查看内存占用情况会发现,内存泄漏了!

原因参考论坛中的解释:

layout是需要一个QWidget作为容器的,所有加入layout中的控件都是对应容器的子控件,因此从容器中查找子控件,然后删除是最合适的方法。你原来删除的是QLayoutItem,不是QPushButton,所以有内存泄露,也就是说你只是把QPushButton从layout里面移除了,所以它不显示,但是并不代表这个QPushButton被完全删除了

总结如下:

1、QFormLayout动态删除控件,请注意循环体内的范围,不要是可变的;

2、通过QLayoutItem删除时,一定要记得setParent(0);

3、通过查找控件类的方法,记得不要查找的(layout)布局中的控件,一定要是容器(widgets)内的控件!

参考文章:http://www.qtcn.org/bbs/read-htm-tid-33202.html

继续阅读