Houss_gc
Houss_gc

Reputation: 749

Create ObjectModel from C++ at runtime

Is it possible to create an ObjectModel from c++ at runtime?

I have a plugin based application, where every plugin create a QQmlComponent and setup the signal and slots then give the component to the main app for rendering in a ListView, for this end I want to have a ObjectModel in the c++ side and manipulate it there.

main.qml (main app interface):

import QtQuick 2.9
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2


ApplicationWindow {
    id: qmlMainWindow
    width: 1240
    height: 720
    minimumWidth: 270+600
    minimumHeight: 120+400
    visibility: "Maximized"
    visible: true
    title: "CTC - Tableau de bord"

    GridLayout {
        anchors.fill: parent
        columnSpacing: 0
        rowSpacing: 0
        columns: 2
        rows: 2
        HeaderArea {
            id: headerArea
            Layout.row: 0
            Layout.columnSpan: 2
            Layout.fillWidth: true
            Layout.fillHeight: true
            Layout.minimumHeight: 120
            Layout.maximumHeight: 120
        }
        NotificationArea {
            id: notificationArea
            Layout.row: 1
            Layout.column: 1
            Layout.fillHeight: true
            Layout.maximumWidth: 350
            Layout.preferredWidth: 300
            Layout.minimumWidth: 270
            model: notificationModel
        }
        MainArea {
            id: mainArea
            bgColor: "lightgray"
            Layout.row: 1
            Layout.column: 0
            Layout.fillWidth: true
            Layout.fillHeight: true
        }
    }

}

MainArea item:

import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQml.Models 2.1

Item {
    objectName: "mainArea"

    function addReport(obj) {
        omodel.append(obj);
    }

    property alias bgColor: mainAreaBackground.color
    property ObjectModel omodel
    Rectangle {
        id: mainAreaBackground
        anchors.fill: parent
        color: "white"
        ListView {
            anchors.fill: parent
            model: omodel
        }
    }
}

At first attempt I wanted to access the MainArea item from c++ side and call the addReport function with QQuickItem* returned from a plugin, without luck.

main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QTimer>
#include <QtPlugin>
#include <QPluginLoader>
#include <QDebug>
#include <QtQmlModel>

#include "notificationmodel.h" // model used in the notification area
#include "interfaces/inotification.h" // interface for a plugin
#include "interfaces/ireport.h" // interface for a plugin (of interest for this post)

int main(int argc, char *argv[])
{
    QGuiApplication::setApplicationName("ctc_dashboard");
    QGuiApplication::setOrganizationName("CTC");
    QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication a(argc, argv);

    NotificationModel notificationModel(&a);

    QQmlApplicationEngine engine;

    QPluginLoader ploader; // I load the plugin which his task is to connect 
                           // to a QtRemoteObject on some server and create a QQuickItem 
                           // which will present some statistics.
    ploader.setFileName("plugins/affair_states/AffairStates.dll");

    engine.rootContext()->setContextProperty("notificationModel", &notificationModel);

    engine.load(QString("%1/%2")
                .arg(QGuiApplication::applicationDirPath())
                .arg("qml/main.qml"));
    if (engine.rootObjects().isEmpty())
        return -1;

    if(ploader.load()){
        IReports* plugin = qobject_cast<IReports*>(ploader.instance());
        if(plugin) {
            qDebug() << "Good plugin : " << plugin->name();
            QObject::connect(plugin, &IReports::notify, [&](NotificationModel::Notification n){
                notificationModel.addNotification(n);
            });
            QObject::connect(plugin, &IReports::newReport, [&](QQuickItem* i){
                qInfo() << "Signal recived";
                qDebug() << "New report " << i;
                qInfo() << engine.rootContext()->contextObject()->findChild<QObject*>("mainArea");
                qInfo() << "Omodel " << engine.rootContext()->contextProperty("omodel");
            });
        }
    }

    return a.exec();
}

IReport plugin interface :

#include <QtPlugin>

#include "inotification.h"
#include <QQuickItem>

class IReports: public INotification
{
    Q_OBJECT
public:
    IReports();
    virtual ~IReports();

    virtual QList<QQuickItem*> reports() = 0;
    virtual QString name() const = 0;
    virtual QString sectionName() const = 0;

signals:
    void newReport(QQuickItem* report);

};
#define IReports_iid "dz.ctc.dashboard.interfaces.IReports"
Q_DECLARE_INTERFACE(IReports, IReports_iid)

Main app screenshoot

Upvotes: 0

Views: 557

Answers (1)

dtech
dtech

Reputation: 49329

It is possible to create any QML object from C++, although it 99.99% of the cases it is bad practice that you shouldn't be doing, and an indication of wrong design that will most likely come back to bite you later on.

You should not create or manipulate QML objects from C++, what you should have is a well defined C++ interface that is exposed to QML so that QML objects can interact with it.

Whatever it is that you intend on doing, there is most likely a better way to do it. Show us some code so we can give you a more specific answer.

Upvotes: 1

Related Questions