升级到Qt 5.15后,ListView委托中的Parent为null [英] Parent is null in ListView delegate after upgrade to Qt 5.15
问题描述
具有最简单委托的 ListView
会产生很多警告" 21:35:31.911警告T#16084047未知-qrc:/main.qml:15:TypeError:无法读取属性左"为null"
,如果尝试将其设置为代理 anchors
属性并滚动列表(这将导致销毁/创建代理).在Qt 5.12或5.9中不是这种情况.
A ListView
with a most simple delegate produces lots of warnings "21:35:31.911 warning T#16084047 unknown - qrc:/main.qml:15: TypeError: Cannot read property 'left' of null"
if trying to set it's delegate anchors
property and scrolling the list (which makes delegates to be destroyed/created). It was not the case in Qt 5.12 or 5.9.
文件 main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
ListView {
anchors.fill: parent
model: cppModel
delegate: Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 50
Text { text: model.itemName }
}
}
}
文件 main.cpp
:
#include <QAbstractListModel>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtGlobal>
#include <QQmlContext>
#include <iostream>
void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
QString logLine = qFormatLogMessage(type, context, msg);
std::cout << logLine.toStdString() << std::endl;
}
class CppModel: public QAbstractListModel {
// QAbstractItemModel interface
public:
virtual int rowCount(const QModelIndex &parent) const override { return 100; }
virtual QVariant data(const QModelIndex &index, int role) const override {
if (role == (Qt::DisplayRole + 1)) {
return QString("Element %1").arg(index.row());
}
return QVariant();
}
virtual QHash<int, QByteArray> roleNames() const override {
return {{(Qt::DisplayRole+1), "itemName"}};
}
};
int main(int argc, char *argv[])
{
qSetMessagePattern("%{time hh:mm:ss.zzz} %{type} T#%{threadid} %{function} - %{message}");
qInstallMessageHandler(myMessageHandler);
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
CppModel cppModel;
engine.rootContext()->setContextProperty("cppModel", &cppModel);
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
我在做什么错了,以及如何为委托元素正确设置 anchors
?
What I'm doing wrong and how to correctly set anchors
for the delegate element?
推荐答案
这是Qt 5.15中行为更改的结果.在此处报道了第一期,并有更详细的摘要新文档说:
This is the result of a behaviour change in Qt 5.15. The first issue was reported here, with a more detailed summary here. The documentation was updated but may take a little longer to make it onto the website. The new documentation says:
根据需要实例化代表,并且可以随时销毁它们.因此,状态永远不应存储在委托中.代表们是通常作为ListView的contentItem的父项,但通常取决于不管它是否在视图中可见,父级都可以更改,并且有时为空.因此,绑定到父项的属性不建议从委托人内部进行.如果您要代表要填充ListView的宽度,请考虑使用其中之一而是采用以下方法:
Delegates are instantiated as needed and may be destroyed at any time. As such, state should never be stored in a delegate. Delegates are usually parented to ListView's contentItem, but typically depending on whether it's visible in the view or not, the parent can change, and sometimes be null. Because of that, binding to the parent's properties from within the delegate is not recommended. If you want the delegate to fill out the width of the ListView, consider using one of the following approaches instead:
ListView {
id: listView
// ...
delegate: Item {
// Incorrect.
width: parent.width
// Correct.
width: listView.width
width: ListView.view.width
// ...
}
}
因此,您可以:
- 给
ListView
一个id
,并在绑定中使用它,而不是parent
. - 使用附加的属性(
ListView.view
)访问视图. - 检查是否为空(
anchors.left:parent?parent.left:undefined
).
- Give the
ListView
anid
and use it in the binding instead ofparent
. - Use the attached property (
ListView.view
) to access the view. - Check for null (
anchors.left: parent ? parent.left : undefined
).
选项1和2将产生更简洁的代码.
Options 1 and 2 will result in cleaner code.
选项1减少了创建一个 QObject
(每个附加对象是一个 QObject
),但是将委托与该特定视图相关联.
Option 1 results in one less QObject
being created (each attached object is a QObject
) but ties the delegate to that particular view.
选项2更适合作为独立组件的委托,这些委托将与其他 ListView
s一起重用.
Option 2 is better for delegates that are standalone components that will be reused with other ListView
s.
这篇关于升级到Qt 5.15后,ListView委托中的Parent为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!