首页 > 解决方案 > qml:DelegateModel + Package 使委托暂时具有 null 父级

问题描述

当使用PackageStateParentChange将委托重新设置为多个视图之一时,在重新评估绑定时,该委托似乎暂时有一个 null 父级。如果委托绑定到.width 或类似文件,这会导致错误。

这很令人不安,因为如果将初始状态更改为其他选项,Qt 发布的Package示例会显示相同的问题

(重现:复制 ..../Qt/Examples/Qt-5.14.1/quick/views/package/{view.qml,Delegate.qml} 并将 view.qml 中的初始upTo值从 0 更改为 7,然后运行“qmlscene view.qml”。)。

下面是 Qt 示例的简化,带有一个常量state。活动状态使用定义宽度的ParentChange;这不知何故导致委托暂时有一个空父级,并且 width:parent.width 的绑定出现错误:

test.qml 第 26 行:TypeError:无法读取 null 的属性“宽度”

是什么导致了这种情况,或者更确切地说,如何避免它?而且,鉴于 Qt 的示例具有与上述相同的问题,Package 机制如何工作?

import QtQuick 2.0
import QtQml.Models 2.1

Rectangle {
    width: 300; height: 400

    ListModel {
        id: myModel
        ListElement { display: "One" }
        ListElement { display: "Two" }
        ListElement { display: "Three" }
    }
    DelegateModel {
        id: visualModel
        model: myModel
        delegate:
          Package {
            Rectangle { id: rectA;
              width: 40; height: 25; Package.name: 'pkgA'
            }
            Rectangle { id: rectB;
              width: 40; height: 25; Package.name: 'pkgB'
            }
            Rectangle {
                id: wrapper
                width: parent.width; // ERROR HERE: parent is sometimes null!
                height: 25
                color: 'lightsteelblue'
                state: 'state1'
                states: [
                    State {
                        name: 'state1'
                        ParentChange {
                            target: wrapper; parent: rectB
                            width: rectB.width; height: rectB.height // **CAUSES ERROR**
                        }
                    }
                ]
                Component.onCompleted: {
                  console.log("wrapper onCompleted: parent is",parent);
                }
                onParentChanged: {
                  console.log("wrapper parent changed to",parent);
                }
            }
          }
    }
    ListView {
        width: 300; height: 200
        model: visualModel.parts.pkgA
    }
    ListView {
        width: 300; height: 200
        model: visualModel.parts.pkgB
    }
}

标签: qtqml

解决方案


好的,终于想通了。你从这个开始:

width: parent.width

这是一个 Qt 绑定表达式。它将随时更新parentparent.width更改。当第wrapper一次创建 Rectangle 时,parent正确地开始null- 它还没有视觉父级。

但是然后你像这样做一个 ParentChange:

    ParentChange {
        target: wrapper; parent: rectB
        width: rectB.width; height: rectB.height // **CAUSES ERROR**
    }

中的width任务ParentChange是删除您以前的绑定并在其上放置一个新的rectB.width宽度。这就是为什么控制台登录原始绑定在此时停止触发的原因。该绑定已被删除。

所以,最重要的是,你误解了正在发生的事情。Parentnull 将开始并通过触发state前的初始值进行设置。Component.onCompleted然后,当您执行 时ParentChange,您正在清除原始绑定,因此您进行的调试具有误导性。

所以回到你原来的问题,要停止错误,只需完全删除widthheight绑定,wrapper然后让ParentChange应用那些不会引发错误的绑定。


推荐阅读