我正在尝试编写一个包含一些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>
答案 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/]