升级到Qt 5.15后,ListView委托中的Parent为null [英] Parent is null in ListView delegate after upgrade to Qt 5.15

查看:102
本文介绍了升级到Qt 5.15后,ListView委托中的Parent为null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具有最简单委托的 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
        // ...
    }
}

因此,您可以:

  1. ListView 一个 id ,并在绑定中使用它,而不是 parent .
  2. 使用附加的属性( ListView.view )访问视图.
  3. 检查是否为空( anchors.left:parent?parent.left:undefined ).
  1. Give the ListView an id and use it in the binding instead of parent.
  2. Use the attached property (ListView.view) to access the view.
  3. 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 ListViews.

这篇关于升级到Qt 5.15后,ListView委托中的Parent为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆