模拟在QML中实例化的C ++类

时间:2019-11-01 14:31:26

标签: c++ qt mocking qml

我正在尝试编写一个包含一些QML文件和一些C ++类的插件,这些插件提供较低级别的功能并与另一个应用程序通信。它们由QML组件使用。 我希望能够通过QML管理这些C ++对象的生存时间(即,应在加载QML文件时创建它们,并在销毁QML时销毁它们),同时仍然能够模拟C ++对象。

到目前为止,我尝试了几种不同的方法。理想情况下,结果是我可以在要编辑的QML文件上使用qmlscene,并在该文件旁边有一个dummydata文件夹,其中包含实例化C ++类的模拟。 如果我尝试在继承自qmlRegisterType的插件类中使用QQmlExtensionPlugin(类似于https://qmlbook.github.io/ch17-extensions/extensions.html中的示例),然后将结果库传递给qmlscene, QML文件不会使用模拟,而是实例化一个C ++对象。这意味着有时候,我需要开始一些逻辑工作,才能将一些模拟数据放入我的QML文件中。

似乎“ QML书”中的示例建议在将任何C ++引入QML之前,先通过模拟完全设计QML组件。有没有办法使可持续发展呢?我猜想,通过注释掉相应的行,我可以避免将qmlRegisterType用于我想模拟一段时间的C ++类,但是我不想这样做。

我尝试的另一种方法是使用中央C ++控制器类中的QQMLContext::setContextProperty。这使我能够将C ++对象从C ++传递到QML并使用虚拟数据,但是对象的生存期将不会由QML组件管理,而是由C ++管理。同样,每个类都应该被实例化多次,正确连接信号很容易出错。这是我到目前为止发现的:

auto proxy = std::make_shared<Proxy>();
//make `proxy` object known in QML realm
_qmlEngine.rootContext()->setContextProperty("proxy", proxy.get());

connect(&_qmlEngine, &QQmlApplicationEngine::objectCreated,
        [&proxy](QObject *object, const QUrl &url) {
            if (url == QUrl("qrc:/imports/Common/TestWindow.qml")) {

                // make sure the proxy is not destroyed when leaving scope of this function
                connect(qobject_cast<QQuickWindow *>(object),
                        &QWindow::visibilityChanged, // as a dirty workaround for missing QWindow::closing signal
                        [proxy]() mutable { proxy.reset(); }); // delete proxy when closing TestWindow
            }
        });

_qmlEngine.load(QUrl("qrc:/imports/Common/TestWindow.qml"));

是否存在一种“舒适的”方式来模拟在QML中实例化且最初来自C ++的数据,或者至少存在一种将这种C ++对象的生存期附加到QML对象的生存期的好方法吗? / p>

1 个答案:

答案 0 :(得分:0)

我解决此问题的方法如下:

实际的生产应用程序将使用C ++插件,仅包含C ++文件,而不包含QML。

为了进行模拟,有一个与C ++插件同名的QML模块,其中包含QML文件,这些文件提供与等效C ++类相同的接口。除了常规的QML包含内容之外,该模块还传递给qmlscene

如果C ++类头看起来像这样:

class Proxy : public QObject
{
  Q_OBJECT

  public:
    Q_PROPERTY(int foo)
    Q_INVOKABLE void start();

  signals:
    void started();
}

像这样,此类可供QML使用:

qmlRegisterType<Proxy>("Logic", 1, 0, "Proxy");

QML模拟(在文件Proxy.qml中)如下所示:

import QtQml 2.12

QtObject {
  signal started()
  property var foo: 42
  function start() { console.log("start") }
}

并可以使用如下形式的qmldir文件导入QML:

module Logic

Proxy 1.0 Proxy.qml

qmlscene的最终调用是

qmlscene [path/to/prototype/qml] -I [path/to/folder/containing/proxy/mock/]