【问题标题】:Is the order of loading of Qt Quick children specified?是否指定了 Qt Quick 子项的加载顺序?
【发布时间】:2018-02-22 02:57:26
【问题描述】:

例如是否保证children的初始化顺序与它们在源代码中出现的顺序一致?

注意:“初始化孩子”是指“初始化孩子及其所有孩子、后代、绑定等”。

【问题讨论】:

  • 它是一棵树,对象是按顺序创建的。对于绑定,没有任何保证,顺序是任意的。它发生在单独的传递中,并且可以根据表达式层次结构进行多次传递。根据经验,您不应在根对象处依赖比整个 QML 文件更细的粒度。如果您想更严格地控​​制顺序,请强制实例化树。
  • @dtech:“对象是按顺序创建的。” - 但是什么命令? :)
  • 自然树的顺序,从根到顶叶。我不知道具体的实现,但通用逻辑要求您迭代树并创建每个对象,推送和弹出当前分支对象以用作父对象。极不可能在父级之前创建子级,然后创建父级,然后您将所有子级都返回父级...
  • 假设以下结构 A { B { C {} D {} } E {} },对象将按该顺序创建。首先是根 A,然后是它的子 B,然后是 B 的子 C 和 D,最后是 E。同样,不能保证,只是常识,这是最有效和最直接的方式。那只是你的创造。挂钩绑定表达式很容易导致网络混乱。
  • @StefanMonov 肯定的,把自己打晕:code.qt.io/cgit ;)

标签: qt qml qtquick2 order-of-execution


【解决方案1】:

可以通过一个简单的测试来验证对象创建的顺序。

class Test : public QQuickItem {
    Q_OBJECT
  public:
    Test(QQuickItem * p = 0) : QQuickItem(p) { qDebug() << this; }
};

然后:

  Test {
    objectName: "a"
    Component.onCompleted: console.log(objectName, this)
    Test {
      objectName: "b"
      Component.onCompleted: console.log(objectName, this)
      Test {
        objectName: "c"
        Component.onCompleted: console.log(objectName, this)
      }
      Test {
        objectName: "d"
        Component.onCompleted: console.log(objectName, this)
      }
    }
    Test {
      objectName: "e"
      Component.onCompleted: console.log(objectName, this)
    }
  }

输出如下:

Test(0x6a7378, parent=0x0, geometry=0,0 0x0)
Test(0x6a73d8, parent=0x0, geometry=0,0 0x0)
Test(0x6a7438, parent=0x0, geometry=0,0 0x0)
Test(0x6a7498, parent=0x0, geometry=0,0 0x0)
Test(0x6a74f8, parent=0x0, geometry=0,0 0x0)
qml: a Test(0x6a7378, "a")
qml: e Test(0x6a74f8, "e")
qml: b Test(0x6a73d8, "b")
qml: d Test(0x6a7498, "d")
qml: c Test(0x6a7438, "c")

这表明对象构造函数确实被称为自下而上。

另请注意,onCompleted 的顺序不同,具体取决于该处理程序的安装位置。如果您像这样将Test 包裹在Obj.qml 中:

Test {
  id: rectangle
  Component.onCompleted: console.log(objectName, this)
}

并像这样声明结构:

  Obj {
    objectName: "a"
    Obj {
      objectName: "b"
      Obj {
        objectName: "c"
      }
      Obj {
        objectName: "d"
      }
    }
    Obj {
      objectName: "e"
    }
  }

然后你会得到一个一致的“从后到前”的输出,这是你在第一个场景中没有得到的:

Test(0x4b2458, parent=0x0, geometry=0,0 0x0)
Test(0x4b24b8, parent=0x0, geometry=0,0 0x0)
Test(0x4b2518, parent=0x0, geometry=0,0 0x0)
Test(0x4b2578, parent=0x0, geometry=0,0 0x0)
Test(0x50f9d68, parent=0x0, geometry=0,0 0x0)
qml: e Test(0x50f9d68, "e")
qml: d Test(0x4b2578, "d")
qml: c Test(0x4b2518, "c")
qml: b Test(0x4b24b8, "b")
qml: a Test(0x4b2458, "a")

然而,这一切都反映了对象创建的顺序,而不是对象完成的顺序,这涉及到一堆其他的东西,可以以任意顺序执行,具体取决于绑定表达式结构。

简而言之,你不应该真的依赖那个顺序,如果你这样做了,你就做错了。你不应该依赖任何比整个 QML 源代码树完成更精细的东西,qtquick 引擎本身会注意延迟绑定表达式的 初始化 等,直到整个对象树完成,所以你不会'没有问题,它会自动发生,但是依赖任何较低级别和更细粒度的东西是设计中的潜在缺陷,应该避免。如果您想要更明确的初始化顺序,请给您的对象 ID,并为整个 qml 文件执行一个初始化表达式,该表达式将所有内容连接在一起。该表达式中的语句将按照它们定义的顺序执行。

【讨论】:

  • [...] 你不应该真的依赖于那个顺序[...] 当有人忘记通过属性暴露孩子并且你需要时,这个顺序变得很有趣通过children[index] 访问这些孩子,因为它们按创建顺序附加到此列表中(除非它们后来被重新设置为父对象) - 所以如果你想设置QtQuick.Controls 1.x-Objects 的样式,你可以去源代码可轻松确定在此列表中的哪个位置可以找到要更改属性的部分。
  • 这不是一个“稳定”的界面,我个人不会那样做。由于多种原因,该顺序可能会发生变化。我宁愿复制控制源和接口我需要的东西。
  • 我认为它是一个稳定的接口,据我所知,它不再被维护,因此不太可能进行更改。所以让我们说:足够稳定。
  • 不仅源代码更改会导致子索引更改。子项的创建和删除可以在运行时更改。当然,在某些情况下它可能足够安全,但总的来说,我不推荐这种做法。
  • 好吧,你赢了。当然,依赖私有实现细节绝不是好的做法。
猜你喜欢
  • 2020-08-28
  • 2019-11-12
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 2015-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多