У нас есть довольно большое приложение 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. Этот segfault трудно воспроизвести, но вот верный способ сделать это: с визуальной студией в режиме отладки освобожденная память заполняется 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) устарело.
Теперь мой вопрос:
- Это ошибка QtQuick? Если диалог отменяет регистрацию как 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)