文章目录
一、开篇
在QML中,属性绑定是QML的核心特性,该特性允许我们指定不同对象属性之间的关系。当属性的依赖值发生变化时,该属性将根据指定的关系自动更新。
在QML应用程序运行过程中,QML引擎会自动监视属性的依赖项(即绑定表达式中的变量)。当检测到属性发生更改时,QML引擎会重新计算绑定表达式并将新结果应用到属性中,从而实现对象对其他对象之间的属性绑定。
可见,属性绑定关系存在于多个QML对象类型之间,这是QML的核心特性之一。
在QML中,属性绑定有三种方法实现,本文将描述这三种方法和在实际进行属性绑定时需要注意的事情。
二、属性绑定的三种方法
(2-1)使用冒号(:)进行属性绑定
如下代码:
Text {
id: text1
x: 205
y: 176
width: 230
height: 40
//将slider的value属性与text1的text进行绑定。当slider的value的值改变时将会改变text1的显示文本。
text: qsTr("%1".arg(slider.value))
font.pixelSize: 33
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
『注意』:QML的属性绑定是单向的。的value的值改变时将会改变text1的显示文本;但反过来则不会,即text1的显示文本改变时,slider的
value属性不会发生改变。
(2-2)使用Qt.binding()函数进行属性绑定
在QML中,Qt.binding()函数有两种用法:
第一种方法是:在JavaScript代码中命令式地应用属性绑定,如下代码:
Button {
id: button
x: 270
y: 253
text: qsTr("点击我")
onClicked:
{
text1.text = Qt.binding(function(){return slider.value})
}
}
第二种方法是:在初始化动态构造对象的属性值时应用属性绑定,结合Component.createObject()和Loader.setSource()来使用。
『注意』:
Qt.binding()函数不能在属性绑定声明中使用,例如下列代码:
Item {
width: 50
// 错误的使用方法
property int a: Qt.binding(function() { return x + width })
property int b
Component.onCompleted: {
//....
}
}
(2-3)使用Binding类型来进行属性绑定
在QML中,属性绑定用于指定不同对象的属性之间的依赖关系,除了上述两种方法可用于属性绑定外,Qt还提供了一个Binding类型来实现。该类型在以下两种场景中非常有效:
(1)绑定到不可访问的属性
有时候,我们需要将一个对象的属性绑定到另一个对象的属性上,然而这个对象不是由QML直接实例化的,例如:C++导出到QML的类的属性。这时候,则可以使用Binding类型来建立此依赖关系,Binding可以将任何值绑定到任何对象的属性上。
在C++代码中,app.enteredText属性是被映射到QML中的,我们则可以在QML中使用Binding来更新enteredText属性,例如下列代码:
TextEdit { id: myTextField; text: "Please type here..." }
Binding { target: app; property: "enteredText"; value: myTextField.text }
当TextEdit的Text属性改变时,C++属性enteredText将自定更新。
Binding{
target: text1
property: "text"
value: slider.value
}
(2)条件绑定
在某些情况下,我们可能希望在特定条件满足时修改属性的值,但在其他的情况下则不修改。通常,通过直接绑定的方法无法实现这一点,因为我们必须为所有可能的分支提供属性值。
例如,当我们释放鼠标时,下面的代码片段会产生一个警告。这是因为当鼠标在未按下时,绑定的值是未定义的:
value: if (mouse.pressed) mouse.mouseX
这时候,使用Binding则可以有效解决这个问题,例如下列代码:
Binding on value {
when: mouse.pressed
value: mouse.mouseX
}
三、QML属性绑定的使用细节总结
(3-1)覆盖属性绑定出现的问题
在属性绑定中,静态值的赋值将删除对象之间的绑定。即带有绑定的属性会根据需要自动更新。但是,如果绑定后再从JavaScript语句中为该属性分配一个静态值,那么该绑定将被删除。
如下代码:
Window {
id: window
width: 640
height: 480
visible: true
color: "#99c4e9"
title: qsTr("Hello World")
Text {
id: text1
x: 205
y: 176
width: 230
height: 40
text: qsTr("%1".arg(slider.value))
font.pixelSize: 33
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
Button {
id: button
x: 270
y: 253
text: qsTr("点击我")
onClicked:
{
//如果此点击事件处理函数得以执行,那么text1的text属性将被重新赋值为“999”。此后
//text1对象将与slider对象解除绑定。【那么再滑动slider,text1的文本将不会改变】
text1.text = qsTr("999");
}
}
Slider {
id: slider
x: 459
y: 105
width: 40
height: 315
to: 100
orientation: Qt.Vertical
value: 0
}
}
在上述代码中,存在一个Text、Button和一个Slider,其中,Text的text属性是与Slider的value属性绑定在一起的,当我们滑动Slider时,Text的文本将自动更新。从上述代码可见,在Button的点击事件处理程序中会对Text的text属性重新赋值,所以,该操作将解除Slider和Text之间的绑定。
(3-2)开启属性绑定被覆盖时的提示信息
QML应用程序出现bug的一个常见原因是:意外地使用JavaScript语句的静态值覆盖了绑定。为了帮助我们跟踪调试这类问题,QML引擎能够在强制分配而丢失绑定时,发出提示消息。
为了得到提示信息,我们需要开启qt.qml.binding.removal日志类别的信息输出,如下所示:
在main.c中首先使用如下代码包含日志头文件。:
#include <QLoggingCategory>
然后在main函数下,加入如下代码:
QLoggingCategory::setFilterRules(QStringLiteral("qt.qml.binding.removal.info=true"));
通过上述步骤,就开启了提示信息调试,如果在开发过程中,出现属性绑定覆盖的情况,控制台将会打印出提示信息,如下所示:

(3-3)使用“this”解决属性绑定的歧义
如下代码所示,在Item这个类型范围中,width指的是Item的宽度,而不是Rectangle的宽度。要将Rectangle的高度绑定到它自己的宽度,绑定表达式必须显式引用this.Width,或者使用rect.width。
Item {
width: 500
height: 500
Rectangle {
id: rect
width: 100
color: "yellow"
}
Component.onCompleted: {
rect.height = Qt.binding(function() { return this.width * 2 })
// 此处将打印出200,而不是1000
console.log("rect.height = " + rect.height)
}
}
(3-4)QML与C++混合开发中的属性绑定总结
在QML与C++进行混合开发时,关于属性绑定,需要注意以下两点:
1、在C++中声明属性时,需要添加NOTIFY字段,因为所有属性绑定的执行是由NOTIFY信号推动,如果自定义属性没有定义该信号,那属性绑定极大可能不起作用。如下代码:
Q_PROPERTY(QString m_age READ getAge WRITE setAge NOTIFY ageChanged)
上述代码中,有一个QString类型的属性变量m_age,指定了读、写该属性值的接口函数,同时还使用NOTIFY指定了参数值改变时发出的信号ageChanged。
2.、如果属性值在C++中被修改了,是需要发射NOTIFY指定的属性改变信号的。否则,属性绑定也极大可能不生效。
(3-5)如何实现对象之间的双向绑定
从上文我们已经知道,属性绑定是单向的,如何实现对象之间的双向绑定呢?对于这一点,两个对象之间各做一次属性绑定,即可实现双向绑定。
那么此处如果与C++进行混合编程,当在qml导出c++类属性时,则需要判断该属性值是否真的改变了,然后才发出对应的属性改变信号。否则极有可能出现问题。
本文详细介绍了QML中属性绑定的三种方法:冒号(:)绑定、Qt.binding()函数绑定和Binding类型绑定,并探讨了属性绑定的使用细节,包括覆盖绑定、条件绑定、与C++混合开发的注意事项及双向绑定的实现。

793

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



