【发布时间】:2015-12-17 16:20:12
【问题描述】:
我有一个暴露给 QML 的 C++ 对象,它具有“某种”只读属性,除了该属性仍需要从 QML 设置,因此它定义了一个 WRITE 方法,但除了初始 强制设置它永远不会改变,所以我觉得NOTIFY 是多余的,因为它在使用时已经设置了该值,并且永远不会改变。
但是,QML 并不认同我的感受,而且不管它是否发出“表达式依赖于不可通知的属性”警告。
由于使用属性实例化对象的方式是设置该值的唯一适用方式,因此不可能使用可调用的设置器,因为这样会要求对象已经“完成”,没有它就无法真正完成那个值。因此需要属性机制和WRITE 方法,不幸的是这导致Qt 相信属性会改变。我尝试将属性设置为CONSTANT,但这似乎与使用WRITE 方法并不一致。
我已经设置了一个虚拟信号作为临时措施来处理大量警告,但如果有更优雅的方法来处理这个问题,我更愿意。同样,该设计实际上消除了在初始设置后设置此值的可能性,但由于它是 C++ 对象并且需要基于每个对象设置值,因此不适用于使用 QML readonly property任何一个。是否有不涉及冗余信号的解决方法?
澄清一下,这里的根本问题是,在当前状态下,QML 几乎没有办法初始化对象的只读属性,用 C++ 实现。这样的属性没有设置器(如果有,那么它会发出“取决于...”警告),并且无法将值传递给对象的构造函数。正如我在下面的回答中所描述的,这方面有一些技巧,但它们要么在应用上受到限制,要么相当不方便。在 C++ 中,您甚至可以通过将值传递给在初始化器列表中执行初始化的构造函数,而不是在 QML 中,对每个实例进行 const 成员的初始化。即使在纯 QML 中,只读属性也必须在现场初始化,不可能让它们未初始化(readonly property type name 没有: statement)并将其延迟到实例化并获得每个实例的初始化(Obj { name : initValue })。你可以这样做:
Item { // T.qml
readonly property int r : w
property int w
}
...
T { w: value }
但是它......有点违背了目的......并且考虑到一个属性只能在其实例化的主体中“绑定”一次,我认为这可以被视为一种初始化行为,同时进一步分配或命令式重新绑定 (Qt.binding()) 被禁止。没有冗余通知信号的设置器可以解决问题,但是 qtquick 的实现设计假设如果它有一个设置器,它将发生变化,因此会抱怨它没有通知信号,这是 IMO 的设计疏忽——也就是说,不提供任何方法来在每个实例的基础上初始化 QML 端的只读属性。目前,正如我已经提到的,这 3 种可能的解决方案要么带来开销(有一个通知信号)、限制(在对象创建之前设置值 - 仅适用于动态实例化)或主要的不便(使用 setter 和 getter 插槽而不实现实际属性接口)。
【问题讨论】:
标签: c++ qt properties notifications qml