QT提供的可绑定属性是指这些属性可以绑定到其他值或表达式上(通常是 C++ lambda 表达式)。如果属性是通过表达式进行绑定,该属性会跟随表达式自动更新。可绑定属性由 QProperty 类和 QObjectBindableProperty 类实现,它们都继承自 QPropertyData 类。QProperty 类包含数据对象和指向管理数据结构(QPropertyBindingData)的指针;QObjectBindableProperty 类仅包含数据对象,使用封装的 QObject 来存储指向管理数据结构的指针。也就是说,QProperty 不依赖 QT 的元对象系统(metaobject system),QObjectBindableProperty 则需要和 QObject 一起使用。
属性绑定是 QML 的核心属性之一。它允许指定不同对象将的关系,并在其所依赖对象变更时自动更新属性值。可绑定属性不仅仅用在 QML 代码中, C++代码中都可以使用。使用可绑定属性可以简化编程,从而省略哪些通过跟踪、响应(信号、槽机制)来更新属性的代码。简化编程的示例:https://doc.qt.io/qt-6/qtcore-bindableproperties-example.html
可绑定属性在C++ 代码中的示例
绑定表达式通过读取其它 QProperty 的值来计算绑定属性的值。当绑定表达式依赖的任何一个属性变动时,绑定表达式都会重新计算,并将结果用于对应的绑定属性。
QProperty<QString> firstname("John");
QProperty<QString> lastname("Smith");
QProperty<int> age(41);
QProperty<QString> fullname;
fullname.setBinding([&]() { return firstname.value() + " " + lastname.value() + " age: " + QString::number(age.value()); });
qDebug() << fullname.value(); // Prints "John Smith age: 41"
firstname = "Emma"; // Triggers binding reevaluation
qDebug() << fullname.value(); // Prints the new value "Emma Smith age: 41"
// Birthday is coming up
age.setValue(age.value() + 1); // Triggers re-evaluation
qDebug() << fullname.value(); // Prints "Emma Smith age: 42"
上例中,当 firstname 变动时,绑定表达式都会重新计算 fullname 的值。因此,当最后一个 qDebug() 语句访问 fullname 属性时,返回的是最新的值。
既然绑定表达式是 C++ 方法,那么该方法中就和普通 C++ 方法一样,可以做任何事(例如,调用其它方法)。如果被调用的方法中使用了 QProperty 变量,那么该变量将自动和绑定属性建立依赖关系。
绑定表达式中可以使用任何类型的属性,上例中 age 是 int 类型并转换为了 string 类型,但是依然被 fullname 依赖和追踪。
###可绑定属性的 Getters 与 Setters
在类中使用 QProperty 或 QObjectBindableProperty 声明可绑定属性时,构建 Getters 与 Setters 特别要注意。
- getters
为了确保自动依赖项跟踪系统的正确运行,getter 中需要从底层属性对象中读取值。此外,==不得在 getter 中写入该属性。不能在 getter 中使用重新计算或更新任何内容的设计模式。==因此对于可绑定属性,推荐只使用最简单的 getters。
- setters
为了确保自动依赖项跟踪系统的正确运行,==setter 中不论值是否发生改变都需要将值写入底层属性对象。setter 中的其它任何代码都是错误的。任何使用新值执行的更新操作都应视作 bug,因为当绑定属性通过绑定改变时这些代码不会执行。==因此对于可绑定属性,推荐只使用最简单的 setters。
- Virtual Setter 和 Virtual Getter
可绑定属性的 setter 和 getter 通常应该是最小的,并且只设置属性;因此,==通常不适合将此类 setter 和 getter 设置为 virtual。==这对派生类来说没有任何意义。
但是,某些 Qt 类可能有 virtual setter 的属性。在继承这样的 Qt 类时,重写 setter 需要特别小心。在任何情况下,都必须调用基本的实现才能使绑定正常工作。方法如下:
void DerivedClass::setValue(int val)
{
// do something
BaseClass::setValue(val);
// probably do something else
}
写入可绑定属性的所有规则和建议也适用于此处。调用基类实现后,所有观察者都会收到有关属性更改的通知。所以在调用基类实现之前,需要确保类达到稳定状态(即需要修改的属性都已修

597

被折叠的 条评论
为什么被折叠?



