Qt对象树与拥有权

对象树与拥有权
     Qt中使用对象树(object tree)来组织和管理所有的QObject类及其子类的对象。当创建一个QObject时,如果使用了其他的对象作为其父对象(parent),那么这个QObject就会被添加到父对象的children()列表中,这样当父对象被销毁时,这个QObject也会被销毁。实践表明,这个机制非常适合于管理GUI对象。例如,一个QShortcut(键盘快捷键)对象是相应窗口的一个子对象,所以当用户关闭了这个窗口时,这个快捷键也可以被销毁。
     QWidget 作为能够在屏幕上显示的所有部件的基类,扩展了对象间的父子关系。一个子对象一般也就是一个子部件,因为它们要显示在父部件的区域之中。例如,当关闭一个消息对话框(message box )后要销毁它时,消息对话框中的按钮和标签也会被销毁,这也正是我们所希望的,因为按钮和标签是消息对话框的子部件。当然,我们也可以自己来销毁一个子对象。关于这一部分的内容,大家可以在帮助索引中查看Object Trees &Ownership 关键字。
      在前面的Qt 编程中我们应该看到过很多使用new 来创建一个部件,但是却没有使用delete 来进行释放的问题。这里再来研究一下这个问题。
  新建Qt Gui 应用,项目名称为“myOwnership ”,基类选择QWidget ,然后类名保持“Widget ”不变。完成后向项目中添加新文件,模板选择C++ Class ,类名为“MyButton ”,基类为“QPushButton ”,类型信息选择“继承自QWidget ”。添加完文件后在mybutton.h 文件中添加析构函数的声明:
~MyButton();
 
然后到mybutton.cpp文件中添加头文件#include <QDebug>并定义析构函数:
MyButton ::~MyButton()
{
    qDebug() << "delete button";
}

        这样当MyButton 的对象被销毁时,就会输出相应的信息。这里定义析构函数,只是为了更清楚的看到部件的销毁过程,其实一般在构建新类时不需要实现析构函数。下面在widget.cpp 文件中进行更改,添加头文件:
#include   "mybutton.h"
#include<QDebug>

在构造函数中添加代码:
MyButton   * button   =   new   MyButton ( this );  //  创建按钮部件,指定 widget 为父部件
button-> setText(tr("button"));

更改析构函数:
Widget ::~Widget()
{
    delete ui;    
    qDebug() << "delete widget";
}
       Widget 类的析构函数中默认的已经有了销毁ui 的语句,这里又添加了输出语句。当Widget 窗口被销毁时,将输出信息。下面运行程序,然后关闭窗口,在QtCreator 的应用程序输出栏中的输出信息为:
delete widget
delete button
 
         可以看到,当关闭窗口后,因为该窗口是顶层窗口,所以应用程序要销毁该窗口部件(如果不是顶层窗口,那么关闭时只是隐藏,不会被销毁),而当窗口部件销毁时会自动销毁其子部件。这也就是为什么在Qt 中经常只看到new 操作而看不到delete 操作的原因。再来看一下main.cpp 文件,其中 Widget 对象是建立在栈上的
Widget   w;
w. show();
 
        这样对于对象w,在关闭程序时会被自动销毁。而对于Widget中的部件,如果是在堆上创建(使用new操作符),那么只要指定Widget为其父窗口就可以了,也不需要进行delete操作。整个应用程序关闭时,会去销毁w对象,而此时又会自动销毁它的所有子部件,这些都是Qt的对象树所完成的。
        所以,对于规范的Qt程序,我们要在main()函数中将主窗口部件创建在栈上,例如“Widget w;”,而不要在堆上进行创建(使用new操作符)。对于其他窗口部件,可以使用new操作符在堆上进行创建,不过一定要指定其父部件,这样就不需要再使用delete操作符来销毁该对象了。

        还有一种重定义父部件(reparented )的情况,例如,将一个包含其他部件的布局管理器应用到窗口上,那么该布局管理器和其中的所有部件都会自动将它们的父部件转换为该窗口部件。在widget.cpp 文件中添加头文件 #include   <QHBoxLayout> ,然后在构造函数中继续添加代码:
MyButton   *button2   =   new   MyButton ;
MyButton   *button3   =   new   MyButton ;
QHBoxLayout   *layout   =   new   QHBoxLayout ;
layout-> addWidget(button2);
layout-> addWidget(button3);
setLayout(layout);      //  在该窗口中使用布局管理器
 
        这里创建了两个MyButton 和一个水平布局管理器,但是并没有指定它们的父部件,现在各个部件的拥有权(ownership )不是很清楚。但是当使用布局管理器来管理这两个按钮,并且在窗口中使用这个布局管理器后,这两个按钮和水平布局管理器都将重定义父部件而成为窗口Widget 的子部件。可以使用children() 函数来获取一个部件的所有子部件的列表,例如在构造函数中再添加如下代码:
qDebug() << children();     //  输出所有子部件的列表
 
        这时大家可以运行一下程序,查看应用程序输出栏中的信息,然后根据自己的想法更改一下程序,来进一步体会Qt 中对象树的概念。
 
总结:
  Qt中的对象树很好地解决了父子部件的关系,对于Gui编程是十分方便的,在创建部件时我们只需要关注它的父部件,这样就不用再考虑其销毁问题了。下一节,我们将讲解Qt中的信号和槽的内容。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值