升级到 Qt 5.15 后,ListView 委托中的父级为空
具有最简单委托的 ListView
会产生大量警告 "21:35:31.911 警告 T#16084047 unknown - qrc:/main.qml:15: TypeError: Cannot read如果尝试设置它的委托
.在 Qt 5.12 或 5.9 中并非如此.anchors
属性并滚动列表(这使得委托被销毁/创建),则属性 'left' of null"
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 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
一起重用.
Option 2 is better for delegates that are standalone components that will be reused with other ListView
s.
相关文章