Qt控件在布局内(QFormLayout、QGridLayout等)的动态添加与删除
项目场景:在项目开发过程中,比如报警信息的显示,如果将所有的报警信息都添加至布局内,再以控件隐藏与显示的方式进行报警,这种方法无疑是最简单的,但是如果报警种类过多,但往往需要显示的很少,在界面里面去一个个拖控件或者代码添加都太麻烦,这就需要动态添加与删除了!问题描述:就以下图为例吧:因为电池电芯不固定,可能是8芯可能是16芯,所以1、2、3部分都是动态更新的。且都使用了groupbox容器,不同的
项目场景:
在项目开发过程中,比如报警信息的显示,如果将所有的报警信息都添加至布局内,再以控件隐藏与显示的方式进行报警,这种方法无疑是最简单的,但是如果报警种类过多,但往往需要显示的很少,在界面里面去一个个拖控件或者代码添加都太麻烦,这就需要动态添加与删除了!
问题描述:
就以下图为例吧:
因为电池电芯不固定,可能是8芯可能是16芯,所以1、2、3部分都是动态更新的。
且都使用了groupbox容器,不同的是1、2放置formlayout布局,3放置gridlayout布局。
代码:
动态添加
添加代码很简单,按需要添加即可:
void QFormLayout::addRow(const QString &labelText, QWidget *field)
void QGridLayout::addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment = Qt::Alignment())
但是每次添加前必须将布局里面的控件删除,在操作过程中发现极易出错。
动态删除
- QFormLayout:
- 方法一:(推荐)
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的数据动态更新~
- 方法二:
通过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();
}
}
- 方法三:
通过查找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)内的控件!
更多推荐
所有评论(0)