Qt从布局管理看对象树机制
2018-01-02 22:21
501 查看
对象树机制
Qt提供了一种机制,在析构父对象时,会先析构它的子对象。完成这种机制需要两个条件:1、继承自QObject类。
2、指定parent确认父子关系。
布局管理
我们先做一个小实验,我们要把一个QLineEdit显示到Widget上。当然我们可以直接new一个QLineEdit对象,并在它的构造函数传入this指针来实现,还可以使用move函数来移动它的位置。m_pLineEdit = new QLineEdit(this); m_pLineEdit->move(100,100);
在这里我们要用水平布局来实现。
不指定parent,也不采用布局是不会在界面上显示QLineEdit的。
m_pLineEdit = new QLineEdit;
不指定parent,采用布局实现
m_pLineEdit = new QLineEdit;
QHBoxLayout *m_pHBoxLayout = new QHBoxLayout;
m_pHBoxLayout->setMargin(10);
m_pHBoxLayout->setSpacing(10);
m_pHBoxLayout->addWidget(m_pLineEdit);
this->setLayout(m_pHBoxLayout);
我们再看一个例子
m_pLineEdit = new QLineEdit;
QHBoxLayout m_pHBoxLayout;
m_pHBoxLayout.setMargin(10);
m_pHBoxLayout.setSpacing(10);
m_pHBoxLayout.addWidget(m_pLineEdit);
this->setLayout(&m_pHBoxLayout);
好,现在我们来看两个问题:
1、第一个例子中的m_pHBoxLayout在堆上创建,我们想要delete掉它时怎么找到这个对象?
2、第二个例子中m_pHBoxLayout在栈上创建,似乎没起到布局作用,但是控件为什么显示到了界面上?
首先,通过以上对比,不难发现,实现我们想要的效果,m_pHBoxLayout的生命周期必须是界面的生命周期,不可以在栈上创建,因为跳出作用域后,它就会被析构掉,所以只能创建在堆上,也难怪各种教程上都是用的指针对象,是由问题本身的特点决定的。
我们明确了m_pHBoxLayout必须得new出来,那么怎么找到它并delete掉呢?聪明得同学想到,把它作为类成员,就可以了。是的,这样可以解决问题。那那么多教程都是以上这么写得,难道他们没有考虑内存泄漏?
这时候我们想到对象树机制,如果是这个机制,那么当界面析构得时候,会把它得子对象m_pHBoxLayout先析构掉,这样就不会造成内存泄漏。
于是,我去查看了setLayout的源码,果然!!
void QWidget::setLayout(QLayout *l) { if (!l) { qWarning("QWidget::setLayout: Cannot set layout to 0"); return; } if (layout()) { if (layout() != l) qWarning("QWidget::setLayout: Attempting to set QLayout \"%s\" on %s \"%s\", which already has a" " layout", l->objectName().toLocal8Bit().data(), metaObject()->className(), objectName().toLocal8Bit().data()); return; } QObject *oldParent = l->parent(); if (oldParent && oldParent != this) { if (oldParent->isWidgetType()) { // Steal the layout off a widget parent. Takes effect when // morphing laid-out container widgets in Designer. QWidget *oldParentWidget = static_cast<QWidget *>(oldParent); oldParentWidget->takeLayout(); } else { qWarning("QWidget::setLayout: Attempting to set QLayout \"%s\" on %s \"%s\", when the QLayout already has a parent", l->objectName().toLocal8Bit().data(), metaObject()->className(), objectName().toLocal8Bit().data()); return; } } Q_D(QWidget); l->d_func()->topLevel = true; d->layout = l; if (oldParent != this) { l->setParent(this); l->d_func()->reparentChildWidgets(this); l->invalidate(); } if (isWindow() && d->maybeTopData()) d->topData()->sizeAdjusted = false; }
题外话:QWidget::setLayout: Attempting to set QLayout “” on Widget “Widget”, which already has a layout这个错误的出处正是这里。
其中
l->setParent(this); l->d_func()->reparentChildWidgets(this);
说明了这一切。
QLayout继承自QObject,并指定了父对象this,满足对象树机制的条件。
至此第二个问题也很明了了,m_pHBoxLayout虽然是个栈对象,在它销毁之前通过
l->d_func()->reparentChildWidgets(this);将布局中的控件重新指定了父对象this。于是就出现了以上第二个例子的现象。
总结
采用布局管理的方式进行界面设计,不必手动delete。但是要注意,不满足对象树机制的对象,要谨防内存泄漏,老老实实地把它delete掉。相关文章推荐
- C++ GUI QT 第4版 第六章 布局管理 (3)
- ------------------------Qt布局管理-------------------
- Qt基础 11_布局管理
- 详解 QT 布局管理界面 图文并茂(1)
- Qt之布局管理——(1)基本布局管理
- Qt的布局管理组件
- atitit.软件开发GUI 布局管理优缺点总结java swing wpf web html c++ qt php asp.net winform
- Qt的布局管理
- Qt之布局管理——堆栈窗体
- 详解 QT 布局管理界面 图文并茂
- QT学习 第二章:布局管理--基本布局管理
- Qt之布局管理——停靠窗口
- atitit.软件开发GUI 布局管理优缺点总结java swing wpf web html c++ qt php asp.net winform
- Qt学习07——布局管理
- Qt布局管理: 分割窗口QSplitter类讲解(纯代码实现分割窗口)
- C++ GUI QT 第4版 第六章 布局管理 (1)
- C++ GUI QT 第4版 第六章 布局管理 (4)
- atitit.软件开发GUI 布局管理优缺点总结java swing wpf web html c++ qt php asp.net winform
- Qt 第6章 布局管理(4) 滚动区域 学习笔记
- Qt系列-4、Qt 布局管理(器)