【qml】 QML属性绑定的三种方法

本文详细介绍了QML中属性绑定的三种方法:冒号(:)绑定、Qt.binding()函数绑定和Binding类型绑定,并探讨了属性绑定的使用细节,包括覆盖绑定、条件绑定、与C++混合开发的注意事项及双向绑定的实现。

一、开篇

在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++类属性时,则需要判断该属性值是否真的改变了,然后才发出对应的属性改变信号。否则极有可能出现问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iriczhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值