我注意到QML在下面有一些未指明的问题 - 当委托试图实例化包含它的对象(委托就是)。
考虑这个简单的树构建器示例:
// Object.qml
Row {
property int c : 0
Rectangle {
width: 50
height: 50
color: "red"
border.color: "black"
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.LeftButton) c++
else if (c) c--
}
}
}
List { model: c }
}
// List.qml
Column {
property alias model : r.model
Repeater {
id: r
delegate: Object {} // wont work
}
}
在此示例中,Object
包含List
,其中包含一个实例化另一个Object
的委托。然而,它没有工作,没有错误消息,即使在调试模式下,应用程序窗口根本不会出现,而且从内存使用的外观来看,它无可救药地被遗忘在某处。它也不会崩溃。它只是没有用。
我首先怀疑这是QML的短视实施细节中的另一个,其高尚目标是防止意外无限递归。但是,在这种情况下不存在这样的危险,因为即使两个对象相互实例化,该过程也由"模型"控制。
它也恰好工作"完美无缺"如果"间接"添加,例如:
Column {
property alias model : r.model
Repeater {
id: r
delegate: Loader { source: "Object.qml" }
}
}
如果代理人从Object
替换为代理Loader
的{{1}},则可以正常使用,我认为因为它不会触发愚蠢的交叉引用检查哪个中断执行。
你可能会问为什么我根本不使用第二种情况,而答案很简单 - 这是一个简单的例子,它可以,但在我的实际生产代码中,这打破了我用级联制作的非常复杂的东西负xy空间中的子项目数量,并在其间插入Object
只会导致它被杀死,而我却找不到让它工作的方法。
我还注意到委托在从同一个源,交叉引用或自引用中的Loader
实例化树示例时有完全相同的问题 - 当使用这种类型的实例化递归时,应用程序会卡住同样的方式 - 没有错误,没有警告,没有崩溃,没有窗口,没有任何东西。
知道发生了什么以及如何解决这个问题?我的钱是无限递归保护,假设它是无限的,即使它实际上是受控制的,也是非常有限的递归。
编辑:另请注意,以这种方式包装它并不会Component
。它仅在delegate: Component { Object {} }
未被引用为实例时才有效,因此无论实际情况如何,它看起来都是非常肤浅的检查对象是否相互包含。正如预期的那样,如果包装被移动到Object
:
Object
更新:
我也注意到了这一点:
Loader {
Component.onCompleted: setSource("List.qml", {"model": Qt.binding(function() {return c})})
}
哪个也不起作用。这次在控制台中有一些实际输出,说// Obj.qml
Item {
id: main
property Obj thisObj : main
}
它真的不是,因为它在类型属性的上下文中使用,而不是值/实例。
似乎递归实例化在QML中进行检查并且从根本上打破了,如果在对象树的主体中找到文字QML元素类型自/交引用,它们就完全没有产生任何内容,并且当它引用时产生错误输出用于指定属性类型,即使QML对象属性实际上实现为引用而不是实例。
我还发布了一个bug report并提出如何区分实际的无限递归和自我或交叉引用的情况,实际上不无限递归,这很简单 - 只需要#&# 39;如果引用是属性类型或代理内部,则触发。