Создать ObjectModel из C++ во время выполнения

Можно ли создать ObjectModel из C++ во время выполнения?

У меня есть приложение на основе плагинов, где каждый плагин создает QQmlComponent и настроить сигнал и слоты, а затем дать компонент для основного приложения для рендеринга в ListViewдля этого я хочу иметь ObjectModel в сторону C++ и манипулировать им там.

main.qml (основной интерфейс приложения):

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:

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

С первой попытки я хотел получить доступ к элементу MainArea со стороны C++ и вызвать функцию addReport с помощью QQuickItem*, возвращаемого из плагина, но не повезло.

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:

#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)

Скриншот главного приложения

1 ответ

Решение

Можно создать любой объект QML из C++, хотя в 99,99% случаев это плохая практика, которую вам не следует делать, и указание на неправильный дизайн, который, скорее всего, вернется к вам позже.

Вы не должны создавать или манипулировать объектами QML из C++, у вас должен быть четко определенный интерфейс C++, который доступен для QML, чтобы объекты QML могли взаимодействовать с ним.

Что бы вы ни собирались делать, скорее всего, есть лучший способ сделать это. Покажите нам код, чтобы мы могли дать вам более конкретный ответ.

Другие вопросы по тегам