0

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

23
  • So how is the ObjectModel defined? Where exactly does it come from? Commented Aug 3, 2017 at 13:01
  • it come from the Qt library it's a standard model that render its objects. and in my case I want to render some qquickitems that are issued from the application plugins. Commented Aug 3, 2017 at 13:07
  • I mean it is in the plugin right? Why are you using a regular library? There is the dedicated QQmlExtensionPlugin which as the name suggest is specially for QML. Commented Aug 3, 2017 at 13:09
  • It's not a qml plugin its a simple cpp plugin which construct a qml component create it and pass it to the main app fro rendering in the mainArea. the ObjectModel is a Qt qml Model not me who developed it, I am just using it to render the items issued from my cpp plugin. Commented Aug 3, 2017 at 13:10
  • So you want to create a QML object that is not defined in QML (rather than just instantiating a QML object from C++), entirely from C++. Commented Aug 3, 2017 at 13:12

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I edited the text and added some code, hope it will help see clearly the problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.