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.
File 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 }
}
}
}
File 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();
}
Link to full source code
What I'm doing wrong and how to correctly set anchors
for the delegate element?
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:
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 // ... } }
So, you can either:
ListView
an id
and use it in the binding instead of parent
.ListView.view
) to access the view.anchors.left: parent ? parent.left : undefined
).Options 1 and 2 will result in cleaner code.
Option 1 results in one less QObject
being created (each attached object is a QObject
) but ties the delegate to that particular view.
Option 2 is better for delegates that are standalone components that will be reused with other ListView
s.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With