我们有一个相当大的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析构函数中会发生段错误。这个段错误很难重现,但这是实现它的一种可靠方法:使用Visual Studio处于调试模式时,释放的内存中充满了0xDDDDDD,并且每次触发段错误。
可以在此处找到完整的示例应用程序: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)
答案 0 :(得分:5)
我有很多次这个问题,我不认为这是一个错误,更像是设计限制。您获得的隐式行为越多,您拥有的控制就越少,导致不适当的对象销毁订单和对悬空引用的访问。
在很多情况下,这种情况可能会发生,并且会自行发生#34;因为你超越了琐碎的界限&#34;通过书&#34; 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
}
}
孩子与财产不同。仍然收集属性,但它们不是父级。
至于实现动态内容&#34;事情,我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模式正确,或者是 有更好的方法吗?声明a时也会发生这种情况 默认属性别名。
上次我没有看过它,但至少在几年前它已经开始了。将对象声明为儿童实际上成为其他对象的孩子肯定会很好,但当时这是不可能的,但仍然可能不是。因此需要涉及对象模型和列表视图的稍微详细的解决方案。如果您调查此事并找到不同的内容,请发表评论告诉我。
答案 1 :(得分:2)
我相信你不能在var中声明一个Window对象。在我的测试中,SubWindow永远不会打开,有时会在启动时破坏。
可以在Item内或另一个Window内声明一个Window;在这种情况下,内部窗口将自动变为&#34;瞬态为&#34;外窗 请参阅:http://doc.qt.io/qt-5/qml-qtquick-window-window.html
将您的代码修改为:
Window {
visible: true
PFDialog {
content: Text { text: "Foobar" }
}
}