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

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

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

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

}

Элемент основной области:

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 со стороны С++ и вызвать функцию addReport с QQuickItem*, возвращенным из плагина, но безуспешно.

основной.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)

Главный скриншот приложения


person Houss_gc    schedule 03.08.2017    source источник
comment
Так как же определяется объектная модель? Откуда именно?   -  person dtech    schedule 03.08.2017
comment
это взято из библиотеки Qt это стандартная модель которые отображают его объекты. и в моем случае я хочу отобразить некоторые qquickitems, которые выдаются из плагинов приложения.   -  person Houss_gc    schedule 03.08.2017
comment
Я так понимаю это в плагине? Почему вы используете обычную библиотеку? Существует специальный QQmlExtensionPlugin, который, как следует из названия, специально предназначен для QML.   -  person dtech    schedule 03.08.2017
comment
Это не плагин qml, это простой плагин cpp, который создает компонент qml, создает его и передает в основное приложение для рендеринга в mainArea. ObjectModel - это модель Qt qml, а не я, разработавшая ее, я просто использую ее для визуализации элементов, выдаваемых из моего плагина cpp.   -  person Houss_gc    schedule 03.08.2017
comment
Итак, вы хотите создать объект QML, который не определен в QML (вместо того, чтобы просто создавать экземпляр объекта QML из C++), полностью из C++.   -  person dtech    schedule 03.08.2017
comment
Да, я хочу создать сигнал и слоты подключения компонента и отобразить его из cpp. просто процесс создания выполняется на уровне плагина приложения, а не на уровне приложения, это своего рода динамический компонент qml, где ничего не известно только о том, что это QQuickItem, который должен отображаться в списке MainArea.   -  person Houss_gc    schedule 03.08.2017
comment
Что это за компонент, что он содержит? Я имею в виду, что легко создавать материалы QML из C++ (и неправильно), но вам нужно либо указать файл .qml, либо предоставить строку, содержащую код qml, в качестве источника. Это не происходит из воздуха, нет общедоступного API для создания qml из C++ без кода qml.   -  person dtech    schedule 03.08.2017
comment
Конечно, компонент представляет собой файл qml.   -  person Houss_gc    schedule 03.08.2017
comment
Так в чем собственно проблема? Существующий ответ уже ссылается на документацию по созданию объектов QML из С++?   -  person dtech    schedule 03.08.2017
comment
проблема заключается в том, как создать тип QML ObjectModel из С++ и если возможно вставить компонент, созданный с помощью одного QQmlEngine, в другой движок.   -  person Houss_gc    schedule 03.08.2017
comment
Сколько движков QML вы используете?   -  person dtech    schedule 03.08.2017
comment
на данный момент два, один в основном приложении и один в плагине приложения. но в итоге будет столько движков сколько плагинов.   -  person Houss_gc    schedule 03.08.2017
comment
Это становится беспорядочным. Итак, вы хотите, чтобы несколько движков QML работали одновременно и использовали объекты из одного движка в другом движке? Или вы хотите иметь какой-то плагин, определяющий какой-то тип QML, который вы хотите использовать в базовом приложении?   -  person dtech    schedule 03.08.2017
comment
Во-первых, у меня здесь нет плагина расширения qml, плагин, который у меня есть, подключается к серверу, получая некоторую информацию, представляя ее в компоновке qml, которая будет создана с помощью этого движка плагина и отображена в основном движке приложения.   -  person Houss_gc    schedule 03.08.2017
comment
Ну, не повезло, я не думаю, что это даже возможно. Я действительно не понимаю, почему вам нужно несколько движков для подключения к серверу для получения некоторой информации - для этого вам не нужен QML, вы должны получать свою информацию через обычный QObject и использовать его в качестве источника данных в вашем основном приложении. . Честно говоря, не похоже, что у вас есть четкое представление о том, что вы делаете.   -  person dtech    schedule 03.08.2017
comment
Я не помню какой-либо документации по этому поводу, и объекты IIRC на самом деле тесно связаны с движком, в котором они созданы, вы даже не можете изменить контекст для объекта, не говоря уже о движке. Еще раз, что бы вы ни хотели сделать, определенно есть лучший способ, который также будет иметь дополнительное преимущество работы;)   -  person dtech    schedule 03.08.2017
comment
Возможно, вы правы, я мог бы создать простую информацию о выборке модели и добавить элементы в модель, но я хочу, чтобы представленные элементы были более динамичными, например, я могу просто получить код qml из базы данных, создать элемент на лету и визуализировать его.   -  person Houss_gc    schedule 03.08.2017
comment
Ну, для этого вам не нужны никакие плагины или код C++, вы можете просто создать объект QML из текстовой строки непосредственно из QML: stackoverflow.com/questions/16002310/   -  person dtech    schedule 03.08.2017
comment
Черт возьми, вам даже не нужен сервер на другой стороне, вы можете напрямую загрузить QML с http   -  person dtech    schedule 03.08.2017
comment
А как насчет обработчика сигналов?? Могу ли я подключить его к элементу, который создает компонент во время выполнения?   -  person Houss_gc    schedule 03.08.2017
comment
Думаю, мне нужно более четко объяснить цель моего приложения, извините за этот беспорядок: p   -  person Houss_gc    schedule 03.08.2017
comment
Да, конечно, однако, если возможно, лучше предварительно реализовать их в QML. В большинстве случаев вам просто нужен доступ к основному объекту, который можно сделать с помощью синглтона, свойства динамической области или даже добавить к объекту qml, который создается в виде параметра. И да, всегда полезно объяснить, что вы хотите сделать хорошо, когда вы просите других о помощи в этом.   -  person dtech    schedule 03.08.2017
comment
Хорошо, спасибо, это хороший способ следовать параметру.   -  person Houss_gc    schedule 03.08.2017


Ответы (1)


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

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

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

person dtech    schedule 03.08.2017
comment
Я отредактировал текст и добавил немного кода, надеюсь, это поможет ясно увидеть проблему. - person Houss_gc; 03.08.2017