Qt窗口部件的树型结构
Qt的窗口系统的重要特性之一就是所谓的树型结构,即所有的窗口部件本身也是容器,一个窗口部件可包含任意数量的子部件,子部件在父部件的区域内显示,父部件和子部件之间形成一种树型结构以便于维护——当父部件被删除的时候,它所包含的所有子部件都会被自动删除,这大大的方便了部件之间的内存管理。
这种部件之间的树型结构主要得益于我们前面提到的Qt元对象系统,元对象系统除了实现Qt中一些重要的机制比如信号和槽以及属性等等,也附带的利用了QObject作为顶级父类的这一前提,来实现子部件的自动删除机制。事实上不仅是窗口部件之间有这种树型结构,对所有从QObject继承而来的类都可以形成这种树型结构。
要注意区分这种树型结构与父类子类所形成的类似结构:窗口部件之间的树型结构是一种对象之间的关系,而不是类之间的关系,我们说父部件与子部件并不意味着它们分别是父类与子类的对象。
我们通过一个实际的例子来详细了解一下。为简单起见我们不采用图形部件,仅使用控制台输出来说明子部件是如何自动销毁的:
我们定义了类TreeMem来追踪内存释放的过程,在构造函数中增加参数name用来标记不同的对象,在析构函数和函数printName()用qDebug来打印出对象的名字。
下面的main()函数中,第29行我们定义了顶层对象,然后定义x, y, z三个对象。这里我们所说的父对象就是指的参数QObject *parent的设定:x, y以top为父对象,而z以x为父对象,这样它们之间的树型关系如图1:
由于top定义在栈上,当程序运行到它的作用范围之外时,这个对象就会被自动销毁,这是C++的基本特性之一。当top被自动析构时,它的所有子对象也都会被自动删除,我们来对照一下运行的结果:
可以看到正如我们所期望的,x, y, z也都被自动析构了。注意z的析构在y之前,这说明它的析构被当作x析构的一部分来执行,因而比y的析构要早。
这里我们定义的x, y, z几乎没有其他实际意义,其实通常我们创建的是以QWidget为父类的部件对象,在Qt的实际开发应用中我们发现,以这种树型结构为基础的各部件之间的内存管理非常方便,可以经常用到。
这种部件之间的树型结构主要得益于我们前面提到的Qt元对象系统,元对象系统除了实现Qt中一些重要的机制比如信号和槽以及属性等等,也附带的利用了QObject作为顶级父类的这一前提,来实现子部件的自动删除机制。事实上不仅是窗口部件之间有这种树型结构,对所有从QObject继承而来的类都可以形成这种树型结构。
要注意区分这种树型结构与父类子类所形成的类似结构:窗口部件之间的树型结构是一种对象之间的关系,而不是类之间的关系,我们说父部件与子部件并不意味着它们分别是父类与子类的对象。
我们通过一个实际的例子来详细了解一下。为简单起见我们不采用图形部件,仅使用控制台输出来说明子部件是如何自动销毁的:
| 1 #include <QApplication> 2 #include <QtDebug> 3 4 class TreeMem : public QObject 5 { 6 public: 7 TreeMem(QObject *parent = 0, const QString& name = "") 8 : QObject(parent) 9 { 10 setObjectName(name); 11 qDebug() << "Created: " << objectName(); 12 } 13 14 ~TreeMem() 15 { 16 qDebug() << "Deleted: " << objectName(); 17 } 18 19 void printName() 20 { 21 qDebug() << "Print Name: " << objectName(); 22 } 23 }; 24 25 int main( int argc, char **argv ) 26 { 27 QApplication a( argc, argv ); 28 29 TreeMem top(0, "top"); 30 TreeMem *x = new TreeMem(&top, "x"); 31 TreeMem *y = new TreeMem(&top, "y"); 32 TreeMem *z = new TreeMem(x, "z"); 33 34 top.printName(); 35 x->printName(); 36 y->printName(); 37 z->printName(); 38 39 return 0; 40 } |
下面的main()函数中,第29行我们定义了顶层对象,然后定义x, y, z三个对象。这里我们所说的父对象就是指的参数QObject *parent的设定:x, y以top为父对象,而z以x为父对象,这样它们之间的树型关系如图1:
![]() |
|
图1 对象之间的树型关系 |
| $ ./treemem Created: "top" Created: "x" Created: "y" Created: "z" Print Name: "top" Print Name: "x" Print Name: "y" Print Name: "z" Deleted: "top" Deleted: "x" Deleted: "z" Deleted: "y" |
这里我们定义的x, y, z几乎没有其他实际意义,其实通常我们创建的是以QWidget为父类的部件对象,在Qt的实际开发应用中我们发现,以这种树型结构为基础的各部件之间的内存管理非常方便,可以经常用到。



