HiddenNetwork
HiddenNetwork

Reputation: 97

How to conditionally disable QML Binding to C++ backend?

I am working on QML Application for an embedded system that has a lot of property bindings: many sensor data is displayed throughout different pages of the app. Only 1 page is visible at a time.

When I'm on page 2, the property bindings for page 1 are still taking place, even though visible is set to false on page 1. I wish to have QML respond to binding updates, only when the page is visible, as it would improve performance.

I have tried using the Binding element as described here: Binding QML Type and here: Prevent QML Property Bindings when QML object isn't visible?, but I've noticed that a binding will still update in QML.

I am wondering if it is possible to completely eliminate the binding, if not on page 1.

My code for my attempt at using the Binding Element is attached below. Instead of multiple pages being visible/invisible, I've used a button that toggles a activated property.

main.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, instantiated in 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
}

Upvotes: 0

Views: 881

Answers (1)

Amfasis
Amfasis

Reputation: 4208

Indeed it seems the Binding is still evaluating the value property, but just not assigning it to the text property when the when clause is false. I would consider this buggy, but maybe there is a rationale behind it.

The solution is to use a State as in the following code. This also gives the possibility to state that the value is not being read currently.

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"
                }
            }
        ]
    }
}

Upvotes: 1

Related Questions