如何有条件地禁用 QML 绑定到 C++ 后端?

Posted

技术标签:

【中文标题】如何有条件地禁用 QML 绑定到 C++ 后端?【英文标题】:How to conditionally disable QML Binding to C++ backend? 【发布时间】:2020-03-08 15:06:07 【问题描述】:

我正在为具有大量属性绑定的嵌入式系统开发 QML 应用程序:许多传感器数据显示在应用程序的不同页面中。一次只能看到 1 页。

当我在page 2 上时,page 1 的属性绑定仍在发生,即使在page 1 上将visible 设置为false。我希望 QML 仅在页面为 visible 时响应绑定更新,因为它会提高性能。

我已尝试使用Binding 元素,如下所述:Binding QML Type 和此处:Prevent QML Property Bindings when QML object isn't visible?,但我注意到绑定仍将在 QML 中更新。

我想知道是否有可能完全消除绑定,如果不是在page 1

我尝试使用绑定元素的代码附在下面。我使用了一个切换activated 属性的按钮,而不是多个页面可见/不可见。

ma​​in.qml

Rectangle                                                                               
    x: 280                                                                                         
    y: 20                                                                                          
    width:200                                                                                      
    height:150                                                                                     
    color:"red"                                                                                             
    Text                                         
        y: 76                                                                                      
        width: 85                                                                                  
        height: 67                                                                                 
        text: "off"                                                  
        Binding on text                                                
            value:                                                                                
                // I am surprised to find this prints, regardless of value of controlRect.activated       
                console.log("new value");                                                          
                sensorData.sensorReading.toFixed(1)                                                
                                                                                                  
            when: controlRect.activated                                                            
                                                                                                  
                                                                                                  
                                                                                                  

Rectangle                                                                                         
    id: controlRect                                                                                
    x: 20                                                                                          
    y: 20                                                                                          
    width:200                                                                                      
    height:150                                                                                     
    property bool activated: true                                                                  
    color:                                                                                        
        if (controlRect.activated)                                                                
            "green"                                                                                
                                                                                                  
        else                                                                                      
            "yellow"                                                                               
                                                                                                  
                                                                                                  

    MouseArea                                                                                     
        anchors.fill: parent                                                                       
        onClicked:                                                                                
            console.log("State changed to",!parent.activated);                                     
            parent.activated = !parent.activated                                                   
                                                                                                  
                                                                                             
                                                                                                  

backend.cpp,在 main.cpp 中实例化

#include "backend.h"
#include <QQmlContext>

Backend::Backend(QQmlApplicationEngine* engine, QObject *parent) :
    QObject(parent)

    sensorData = new SensorData();
     QQmlContext* ctxt(engine->rootContext());

    // Connecting back end object instances to front end
    ctxt->setContextProperty("sensorData", sensorData);

sensordata.h

#ifndef SENSORDATA_H
#define SENSORDATA_H
#include <QObject>
#include <QTimer>

class SensorData : public QObject

    Q_OBJECT
public:
    Q_PROPERTY(double sensorReading MEMBER m_sensorReading NOTIFY sensorReadingChanged)

    explicit SensorData(QObject *parent = nullptr);
    ~SensorData() 

private:
    double m_sensorReading;
    double temp;
    QTimer m_timer;

signals:
    void sensorReadingChanged();

public slots:
    void slot_updateReading();

;

#endif // SENSORDATA_H

sensordata.cpp

#include "sensordata.h"
#include <QDebug>

SensorData::SensorData(QObject *parent) :
    QObject(parent)

    // for simulating sensor data
    srand( (unsigned)time(NULL) );
    m_timer.setInterval(100);
    m_timer.setSingleShot(false);
    QObject::connect(&m_timer, &QTimer::timeout, this, &SensorData::slot_updateReading);
    m_timer.start();


// simulate my sensor data
void SensorData::slot_updateReading()
    m_sensorReading = modf(rand() /  100000.0, &temp);
    emit sensorReadingChanged(); // emit for QML binding to update

【问题讨论】:

【参考方案1】:

确实,Binding 似乎仍在评估value 属性,但当when 子句为假时,只是没有将其分配给text 属性。我会考虑这个问题,但也许它背后有一个基本原理。

解决方案是使用State,如下面的代码所示。这也提供了声明当前未读取该值的可能性。

Rectangle
    x: 280
    y: 20
    width:200
    height:150
    color:"red"
    Text 
        id: readout
        y: 76
        width: 85
        height: 67
        text: 
            console.log("new value"); //does not print when deactivated
            sensorData.sensorReading.toFixed(1)
        

        states: [
            State 
                name: "deactivated"
                when: !controlRect.activated
                PropertyChanges 
                    target: readout
                    text: "off"
                
            
        ]
    

【讨论】:

以上是关于如何有条件地禁用 QML 绑定到 C++ 后端?的主要内容,如果未能解决你的问题,请参考以下文章

从高度动态的 C++ 数据模型更新 QML:计时器与属性绑定

如何检索 QML 相机提要并发送到 C++ 后端

如何从 C++ 中删除属性上的 QML 绑定?

如何分析“绑定循环”

如何将 QPixmap 从 C++ 模型传递到 QML?

如何有效地将单个对象的多个 C++ 数据成员公开给 QML?