Object-Widgets-Quick 构造树

时间:2021-10-10 07:27:00
  1. Object Tree

当以某个QObject为父类创建一个QObject时, 它会被添加到该父类的children列表中。 析构时, QObjet 会首先检查自己的children, 依次析构, 然后析构自己,再把自己从父类的children列表中删除。这是一个递归过程, 对于object tree来说, 析构是一个从叶子到根的过程。

如果使用堆存储object tree, 则可以以任何顺序构造、或者析构; 因为显式调用delete时, object tree会删除该节点; 没有调用delete时, object tree会在整棵树被销毁时按照从叶子到根的顺序析构。

如果使用栈存储object tree, 会存在问题。如下所示,根据C++标准,后构造者先析构,系统会首先调用quit的析构函数,把quit从window的object tree中删除, 并析构quit, 然后才会调用 window的析构函数。

int main()

{

    QWidget window;

    QPushButton quit("Quit", &window);

    ...

}

但是如下代码则会存在问题, 系统会首先调用window的析构函数, 把window和quit都析构掉,然后才会调用quit的析构函数, 但是quit已经被析构掉了。

int main()

{

    QPushButton quit("Quit");

    QWidget window;

 

    quit.setParent(&window);

    ...

}

因此使用object tree也不是完全能避免内存问题的, QObject提供了两个函数QObject::dumpObjectTree() 和 QObject::dumpObjectInfo()用于调试 , 如果发现程序有不正常的现象发生, 可以使用这两个函数查看 dump信息。

  1. Widget Tree

Qt Widgets 扩展了object tree体系。 当以某个QWidget为父类创建一个子类时, 它会以父类坐标作为参考坐标,并被父类的边界切割,因此可以显式的看出父子关系;当然它也符合object tree的析构顺序。

  1. Quick Tree

QQuickItem 有一个 visual parent 概念, 也就是(在坐标上)包含它的object。 Visual parent可以不是它的object parent, visual parent存储在 parent 属性中,如果parent为null, 则该item不会被scene渲染。

QQuickWindow::contentItem 存储Qt Quick scene中被渲染的根元素, 如果要添加自己要渲染的元素, 则应该把要渲染的元素添加到contentItem的visual tree中。

Visual parent

当在一个 QQuickItem中声明一个object时,它默认会被加到data列表中, 也可以显式的在data中声明, (如果显式的把它赋值给另一个属性,则不会添加到data中);这时该object的object parent就是声明它的QQuickItem。而如果这个object的类型是Item(QQuickItem), 那么它的visual parent默认就是声明它的QQuickItem, 它会被加到children列表中, 因此, QQuickItem的parent 、children和 object的完全是两码事, 而QWidget的parent-children可以认为即是visual parent,又是object parent。

一个visual parent 会以自己的方式计算childrenRect, 但是不同于Qt Widgets, 它不会自动调整children的大小、位置——当然,一些拥有内建行为的控件除外, 例如Row、Column等,这些控件会排列其children的位置,但是这是继承Item以后添加的特殊动作, 并不属于visual parent的默认行为。

Visual parent默认也不会裁剪超出自己边界的children, 当然这个是可控的, 把clip属性设置为true则会开启裁剪动作。

Visual Coordinate

QQuickItem符合笛卡尔坐标,x、y分别向右向下延伸,子控件以父控件左上作为自己的(0,0)。

Stacking order

QQuickItem把子控件绘制在父控件之上,然后按照声明顺序绘制sibling控件(后声明的绘制在上层),以此递归的决定绘制顺序。这个顺序可以由z属性控制。不过按照先父子、后兄弟的顺序,如果一个控件的父控件在另一个控件树(visual-tree)之下(被遮挡), 那么无论你如果修改该控件的z值,它都不会居于这个控件树之上。