我们有一个相当大的QtQuick应用程序,其中包含许多模式对话框。所有这些模式都具有一致的外观和行为,并具有leftButtons,rightButtons,内容和其他警告小部件。我们使用以下基类(PFDialog.qml):
Window {
property alias content: contentLayout.children
ColumnLayout {
id: contentLayout
}
}
并以以下方式声明对话框(main.qml):
Window {
visible: true
property var window: PFDialog {
content: Text { text: "Foobar" }
}
}
问题在于,当应用程序关闭时,QQuickItem析构函数中会发生段错误。这个segfault很难重现,但是这是一种确保成功的方法:在Visual Studio处于调试模式的情况下,释放的内存将填充0xDDDDDDD并每次都会触发该segfault。
完整的示例应用程序可以在这里找到:https : //github.com/wesen/testWindowCrash
崩溃发生在QQuickItem::~QQuickItem
:
for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
QQuickAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
if (anchor)
anchor->clearItem(this);
}
这样做的原因是我们对话框的内容(上例中的Text项)是主窗口的QObject子级,而是对话框窗口的可视子级。关闭应用程序时,首先会破坏对话框窗口,并且在删除Text项时,对话框窗口(仍注册为changeListener)是陈旧的。
现在我的问题是:
property alias content: layout.children
模式是正确的,还是有更好的方法来做到这一点?声明默认属性别名时也会发生这种情况。为了完整起见,这是我们在应用程序中对其进行修补的方式。当内容更改时,我们会将所有项目重新添加到布局项目中。优雅,大家都同意。
function reparentTo(objects, newParent) {
for (var i = 0; i < objects.length; i++) {
qmlHelpers.qml_SetQObjectParent(objects[i], newParent)
}
}
onContentChanged: reparentTo(content, contentLayout)
我已经多次遇到这个问题,我不认为这是一个错误,更像是一个设计限制。您获得的隐式行为越多,控制就越少,从而导致对象销毁的不适当顺序以及对悬挂引用的访问。
在许多情况下,当您超出琐碎的“ by book” qml应用程序的范围时,这种情况可能会“单独发生”,但是在您的情况下,这是您自己来做的。
如果您要拥有适当的所有权,请不要使用此功能:
property var window: PFDialog {
content: Text { text: "Foobar" }
}
而是使用以下命令:
property Window window: dlg // if you need to access it externally
PFDialog {
id: dlg
content: Text { text: "Foobar" }
}
这是一个很好的理由:
property var item : Item {
Item {
Component.onCompleted: console.log(parent) // qml: QQuickItem(0x4ed720) - OK
}
}
// vs
property var item : Item {
property var i: Item {
Component.onCompleted: console.log(parent) // qml: null - BAD
}
}
孩子与财产不同。仍会收集属性,但它们不是父项。
至于实现“动态内容”的东西,我在以下方面取得了不错的成绩ObjectModel
:
Window {
property ObjectModel layout
ListView {
width: contentItem.childrenRect.width // expand to content size
height: contentItem.childrenRect.height
model: layout
interactive: false // don't flick
orientation: ListView.Vertical
}
}
然后:
PFDialog {
layout: ObjectModel {
Text { text: "Foobar" }
// other stuff
}
}
最后,为了在关闭应用程序之前进行显式清理,可以在主QML文件上实现处理程序:
onClosing: {
if (!canExit) doCleanup()
close.accepted = true
}
这样可以确保在不先进行清理的情况下不会破坏窗口。
最后:
我们的属性别名内容:layout.children模式是否正确,还是有更好的方法呢?声明默认属性别名时也会发生这种情况。
这不是我上次研究它,但至少在几年前。声明为子对象的对象实际上成为其他对象的子对象当然会很好,但是在当时是不可能的,现在仍然不可能。因此,需要涉及对象模型和列表视图的稍微冗长的解决方案。如果您对此事进行调查并发现不同之处,请发表评论以告知我。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句