处理“取决于非NOTIFYable属性”警告

时间:2015-12-17 16:20:12

标签: c++ qt properties notifications qml

我有一个C ++对象暴露给QML,带有“某种”只读属性,除了属性仍然需要从QML设置,因此它定义了WRITE方法,但除了初始强制性设置它永远不会改变,所以我觉得NOTIFY是多余的,因为它在使用时已经设置了该值,并且它永远不会改变。

然而,QML不同意我的感受,并且无论它是否发出“表达式取决于非NOTIFYable属性”警告。

由于使用属性实例化对象的方式是设置该值的唯一适用方式,因此无法使用可调用的setter,因此需要对象已经“完成”并且如果没有那个价值。因此需要属性机制和WRITE方法,不幸的是,Qt认为该属性会发生变化。我尝试将该属性设置为CONSTANT,但似乎没有使用WRITE方法进行叠加。

我已经把一个虚拟信号作为处理大量警告的临时措施,但我更愿意,如果有更优雅的方式来解决这个问题。同样,设计实际上消除了在初始设置之后设置此值的可能性,但由于它是C ++对象并且值需要基于每个对象设置,因此不适用于使用QML {{1也许。有没有涉及冗余信号的解决办法?

只是为了澄清,这里的根本问题是,在当前状态下,QML几乎没有办法初始化用C ++实现的对象的只读属性。这样的属性不会有一个setter(如果然后它会发出“依赖于......”的警告),并且没有办法将值传递给对象的构造函数。正如我在下面的回答中所描述的那样,围绕着这个问题,但是它们要么应用有限,要么相当不方便。在C ++中,您甚至可以在每个实例的基础上执行const成员的初始化,方法是将值传递给在初始化程序列表中进行初始化但不在QML中的构造函数。即使在纯QML中,必须在现场初始化只读属性,也不可能将它们保持未初始化(readonly property没有readonly property type name)并将其延迟到实例化并获得每个实例的初始化({ {1}})。你可以这样做:

: statement

但它......有点挫败了目的......并且考虑到一个属性只能在其实例化体中“绑定”一次,我认为这可以看作是初始化的行为,而进一步的赋值或禁止重新绑定(Obj { name : initValue })。没有冗余通知信号的setter可以做到这一点,但qtquick的实现设计假设如果它有一个setter它会改变,因此会抱怨它没有通知信号,IMO是一个设计监督 - 这是,没有提供任何方法在每个实例的基础上初始化QML端的只读属性。目前,正如我已经提到的,3种可能的解决方案要么有开销(有通知信号),限制(在创建对象之前设置值 - 仅适用于动态实例化)或主要不便(使用setter和getter slot而不实现实际属性接口)。

2 个答案:

答案 0 :(得分:1)

这取决于你需要什么值。

如果在任何属性绑定中使用该属性,那么您将需要通知,否则您最终会依赖于对象实例化和绑定评估的顺序。

E.g。如果它在其他地方的绑定中使用而没有相关的通知信号,那么在第一次评估任何此类绑定之前,您依赖于初始设置。

另一方面,如果该值仅用于初始化C ++端但从未在其他地方的QML中使用过,则可以考虑使用“setter”函数/ slot。

答案 1 :(得分:0)

一种可能的解决方案是只将setter和getter函数暴露给QML,但没有实际属性。它更优雅,更冗长(额外()),但至少它处理控制台中的警告垃圾邮件。它可能最终会更有效率,因为除了消除冗余信号之外,可能会有更少的绑定表达式重新评估观察者实例化。

还有另一种方法,但它只适用于动态创建对象 - 如果以声明方式创建对象,它将无法工作。这种方法涉及在每个对象创建之前调用一个函数,该函数设置一个静态成员值,该对象的构造函数使用该值作为隐式参数来初始化只读属性。因此很明显为什么这只能用于动态创建的对象,在另一种情况下,你不能调用函数并在调用对象的构造函数之前设置值。

还有一些股票API似乎带有没有通知的属性。例如FolderListModel的{​​{1}}属性,因此每次在绑定中使用它时都会生成警告。删除它们的解决方案是使用其他代理属性并将rootFolder属性绑定到它。