c++qtqmlqt5qqmlapplicationengine

How to cleanly expose C++ backend objects to QML, for varying setContextProperties?


I am creating a QML Application with a C++ backend. Different types of cameras can connect to my C++ backend. These cameras have different types of sensors and different numbers of batteries, etc. Depending on what type of Camera is connected, the C++ backend exposes objects to QML using setContextProperty().

Due to the method I am currently using, I have to check what kind of camera is connected (camInfo.type) in QML, and depending on that, bind to the appropriate backend object. This is used throughout my QML Application, so a lot of switch-casing is done, and it is very unmaintainable to support a new camera model.

Is there another way I can expose the varying backend objects to QML, for each different camera model? I do not want to use any switch-cases on camInfo.type in QML.

It would be preferable if I could do something like:

Text {                                         
    y: 50                                      
    x: 50                                      
    text: camera.sensor0Data.sensorReading                                     
    }                                          
}  

where camera.sensor0Data.sensorReading would somehow "map" to one of apertureData.sensorReading, sensor0Data.sensorReading etc. in the backend. And the Text would be visible:false if the connected camera doesn't include that specific sensor.

Snippet of main.qml

Text {                                         
    y: 50                                      
    x: 50                                      
    text: {                                    
        switch(camInfo.type){                  
        case 0: // DSLR                        
            apertureData.sensorReading         
            break                              
        case 1: //MOBILE                       
            sensor0Data.sensorReading          
            break                              
        case 2: //PointandShoot                
            sensor0Data.sensorReading          
        }                                      
    }                                          
}                                              

Text {                                         
    visible: camInfo.type==2 // Point and Shoot
    y: 90                                      
    x: 90                                      
    text: {                                    
        switch(camInfo.type){                  
        case 0: // DSLR                        
        case 1: //MOBILE                       
            "N/A"                              
            break                              
        case 2: //PointandShoot                
            microphoneData.sensorReading       
        }                                      
    }                                          
}                                              

backend.cpp

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

enum Model {
    // types of cameras.
    DSLR=0,
    MOBILE_CAMERA,
    POINT_AND_SHOOT
};

Backend::Backend(QQmlApplicationEngine* engine, QObject *parent) :
    QObject(parent)
{
    // Connecting back end object instances to front end
    QQmlContext* ctxt(engine->rootContext());
    ctxt->setContextProperty("camInfo", deviceInfo);
    ctxt->setContextProperty("videoFeedData", videoFeedData); //video.h

    switch(deviceInfo->m_type){
        case DSLR:
            ctxt->setContextProperty("battery0Data", battery0Data); // battery.h
            ctxt->setContextProperty("battery1Data", battery1Data); // battery.h
            ctxt->setContextProperty("battery2Data", battery2Data); // battery.h
            ctxt->setContextProperty("apertureData", apertureData); // aperture.h
            ctxt->setContextProperty("sensor1Data", sensor1Data); // sensor.h
            ctxt->setContextProperty("sensor2Data", sensor2Data); // sensor.h
            ctxt->setContextProperty("sensor3Data", sensor3Data); // sensor.h
            break;
        case MOBILE_CAMERA:
            ctxt->setContextProperty("sensor0Data", sensor0Data); // sensor.h
            ctxt->setContextProperty("batteryData", batteryData); // battery.h
            break;
        case POINT_AND_SHOOT:
            ctxt->setContextProperty("microphoneData", microphoneData);
            ctxt->setContextProperty("sensor0Data", sensor0Data); // sensor.h
            ctxt->setContextProperty("batteryData", batteryData); // battery.h
            break;
    }
}

Solution

  • As per Dinesh's comment, the idea of using a Loader to load various views appeared to be the method to move forward with. I am posting his answer here for now, to mark this question as answered. If @Dinesh answers it, I will mark his answer as accepted instead.

    Make a class like

    class Camera: public QObject {
        Q_PROPERTY (SensorsModel sensors READ sensors NOTIFY sensorsChanged()) 
    };
    

    Where SensorsModel can be a simple QAbstractListModel exposing a bunch of Sensor objects, something like say Sensor { type: "battery"; minValue: 0; maxValue: 100; value: 50}.

    Then in the QML you can have a Loader loading various Views based on the camera type.