Qt 内存管理与布局管理器

一、new与delete

在C++学习中,new与delete必须成对使用,防止内存泄漏,可是在学习Qt时,我发现很多new,而却几乎找不到delete。在网上搜索得知:Qt完善了C++的内存管理机制,“如果指针对象有父对象,那么父对象在被释放时,会自动释放子对象”。所以我在练习时,创建的控件都传递了this指针,作为其父对象。

但是,当我在练习布局管理器的时候,却出了问题。

二、传递了父对象指针的控件在布局管理器中不能正常显示

 

#include <QApplication>
#include <QTableWidget>
#include <QStringList>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QWidget>
int main(int argc,char *argv[])
{
    QApplication app(argc,argv);    
    QWidget *mainWindow=new QWidget;
    mainWindow->setAttribute(Qt::WA_DeleteOnClose);
    
    QTableWidget *tabStudent=new QTableWidget(3,3,mainWindow);
    tabStudent->setHorizontalHeaderLabels(QStringList()<<"name"<<"sex"<<"age");
    QPushButton *btnInsert=new QPushButton("insert",mainWindow);
    QPushButton *btnDelete=new QPushButton("delete",mainWindow);
    
    QHBoxLayout *bottomLayout=new QHBoxLayout(mainWindow);
    bottomLayout->addWidget(btnInsert);   
    bottomLayout->addWidget(btnDelete);
    
    QVBoxLayout *mainLayout=new QVBoxLayout(mainWindow);
    mainLayout->addWidget(tabStudent);  
    mainLayout->addLayout(bottomLayout);
    
    mainWindow->setLayout(mainLayout);  
    mainWindow->show();
    return app.exec();
}

结果显示,错乱:


经过尝试,不给bottomLayout传递父对象指针时,可以正常显示

#include <QApplication>
#include <QTableWidget>
#include <QStringList>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QWidget>
int main(int argc,char *argv[])
{   
    QApplication app(argc,argv);   
    QWidget *mainWindow=new QWidget;   
    mainWindow->setAttribute(Qt::WA_DeleteOnClose); 
    
    QTableWidget *tabStudent=new QTableWidget(3,3,mainWindow);  
    tabStudent->setHorizontalHeaderLabels(QStringList()<<"name"<<"sex"<<"age"); 
    QPushButton *btnInsert=new QPushButton("insert",mainWindow);  
    QPushButton *btnDelete=new QPushButton("delete",mainWindow); 
    
    QHBoxLayout *bottomLayout=new QHBoxLayout();//修改此处,不传递父对象指针
    bottomLayout->addWidget(btnInsert); 
    bottomLayout->addWidget(btnDelete); 
    
    QVBoxLayout *mainLayout=new QVBoxLayout(mainWindow); 
    mainLayout->addWidget(tabStudent);
    mainLayout->addLayout(bottomLayout);
    
    mainWindow->setLayout(mainLayout);   
    mainWindow->show(); 
    return app.exec();
}


三、布局管理器对内嵌布局管理器和窗体父对象的影响

经过查找帮助文档,终于一探究竟。
首先看一下帮助文档对void QWidget::setLayout ( QLayout * layout )这个函数的说明:

Sets the layout manager for this widget to layout.

If there already is a layout manager installed on this widget, QWidget won't let you install another. You must first delete the existing layout manager (returned by layout()) before you can call setLayout() with the new layout.

If layout is the layout manger on a different widget, setLayout() will reparent the layout and make it the layout manager for this widget.


中文意思大概是:设置窗体的布局管理器为layout。如果窗体已经安装了一个布局管理器,窗体不会再安装另一个布局管理器。
在调用setLayout()安装新的布局管理器之前,你必须首先删除窗体上已经安装的布局管理器。
如果是另一个窗体上安装的布局管理器,setLayout() 会重置这个布局管理器的父对象(为调用setLayout()的窗体)。
由此可以看出,当bottomLayout和mainLayout都指定父对象时,后创建的布局管理器并没有被安装在窗体上,所以不给bottomLayout传递父对象指针时,mainLayout可以被正常安装。
为了验证是否真的不能再次安装,布局管理。做下面的实验:

小提示:

When you use a layout, you do not need to pass a parent when constructing the child widgets. The layout will automatically reparent the widgets (using QWidget::setParent()) so that they are children of the widget on which the layout is installed.

Note: Widgets in a layout are children of the widget on which the layout is installed, not of the layout itself. Widgets can only have other widgets as parent, not layouts.

You can nest layouts using addLayout() on a layout; the inner layout then becomes a child of the layout it is inserted into.

 

我在有道翻译的帮助下,终于把这段话翻译了下来:当你使用布局管理器时,你不需要为子窗体传递父对象指针,布局管理器会自动重置子窗体父亲为安装了这个布局管理器的窗体。在布局管理器内的窗体的父亲是安装了这个布局管理器的窗体,而不是这个布局管理器。窗体的父亲只能是窗体。当使用addlayout的时候,内嵌的layout会成为调用addlayout的那个管理器的子对象。

 

四、总结

学习Qt将近20天,终于写篇成长日记。一定要勤于动手调试。

#include <QApplication>
#include <QTableWidget>
#include <QStringList>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QWidget>

int main(int argc,char *argv[])
{
    QApplication app(argc,argv);

    QWidget *mainWindow=new QWidget;
    mainWindow->setAttribute(Qt::WA_DeleteOnClose);

    QTableWidget *tabStudent=new QTableWidget(3,3);//tabStudent没有父亲
    tabStudent->setHorizontalHeaderLabels(QStringList()<<"name"<<"sex"<<"age");
    QPushButton *btnInsert=new QPushButton("insert");//btnInsert没有父亲
    QPushButton *btnDelete=new QPushButton("delete");//btnDelete没有父亲

    QHBoxLayout *bottomLayout=new QHBoxLayout;//bottomLayout没有父亲
    bottomLayout->addWidget(btnInsert);//btnInsert没有父亲
    bottomLayout->addWidget(btnDelete);//btnDelete没有父亲


    QVBoxLayout *mainLayout=new QVBoxLayout;//mainLayout没有父亲
    mainLayout->addWidget(tabStudent);//tabStudent没有父亲
    mainLayout->addLayout(bottomLayout);//设置bottomLayout的父亲为mainLayout tabStudent,btnInsert,btnDelete没有父亲

    mainWindow->setLayout(mainLayout);
    //设置mainLayout的父亲为mainWindow  tabStudent,btnInsert,btnDelete的父亲为mainWidget
    mainWindow->show();

    return app.exec();
}

/*
可以分析出:mainWindow的直接子对象为;mainLayout,tabStudent,btnInsert,btnDelete
mainLayout的直接子对象为bottonLayout
所以mainWindow释放的时候,会析构mainLayout,tabStudent,btnInsert,btnDelete
mainLayout又会析构bottomLayout
*/


 

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值