我很早以前就对Qt很熟悉,但是我可以对QML / QTQuick与C ++的交互使用一些指导。我觉得这里缺少一些简单的东西,但是有点卡住了。
我正在开发一个嵌入式系统,它显示在串行总线上通信的分布式交换机的状态。串行总线在C ++中一直作为单独的线程运行(一直以来都是Qt),并以轮询方式自动轮询设备以从设备获取更新。
[为此,我找到了一个非常简单的示例,它使用QAbstractList模型通过支持的C ++通过QML属性共享状态。 https://www.youtube.com/watch?v=9BcAYDlpuT8&list=PLo12gBvZwC78nnrZHCBowKf36ZAi7iOLW&index=4&t=0s
最初,该模型看起来不错,我只是简单地加载了一个列表,其中包含了所需的信息,并且可以从UI中看到它。问题是,当后台更改时,如何从C ++访问模型以使更新冒泡到UI。
到目前为止我所做的:
注册模型:
qmlReisterType<ModelDerrivedClass>("DeviceListModel",1,0,"DeviceList")
定义角色:
enum {
OpenRole = Qt::UserRole,
StatusRole
}
定义模型的哈希表
QHash<int,QByteArray> ModelDerrivedClass::roleNames() const
{
QHash<int, QByteArray> names;
names[OpenRole] = "openstatus";
names[StatusRole] = "devicestatus";
return names;
}
使用适当的信息,简单的必要方法等创建简单的结构列表...从上至下就像一个魅力。
如何从下往上访问模型?这些设备将根据UI不需要知道的外部输入来更新状态,但是这些事件需要能够驱动前端。几乎没有考虑到这种情况。
我还考虑过向QML注册设备类型,但无法弄清楚如何将QML对象链接到C ++对象,因此READ / WRITE / NOTIFY属性可与列表中的各个QML对象一起使用。在这种情况下,我将OPEN和STATUS注册为可以直接在QML代码中使用的QML类型的属性,但是我需要将对象实例int C ++与QML对象实例相关联。这是QAbstractListModel适用的方法。
任何帮助将不胜感激。
您有两种选择,但我认为第一种选择更好:
选项1:rootContext
您可以在QQMlEngine
的rootContext上设置属性,该属性将在该qml引擎加载的每个QML文件中可用(请参见Qt docs):
QQuickView view;
view.rootContext()->setContextProperty("currentDateTime",
QDateTime::currentDateTime());
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
view.show();
您应该具有模型的实例:
ModelDerivedClass devices;
QQuickView view;
view.rootContext()->setContextProperty("devices", &devices);
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
view.show();
您现在可以使用ModelDerivedClass
或您自己的方法来更改setData
。
顺便说一句,在此选项中,您不应注册为类型,而应注册为不可创建的类型:
qmlRegisterUncreatableType<ModelDerrivedClass>("DeviceListModel",1,0,"DeviceList", "available as rootContext property 'devices'");
选项2:单例
您可以将ModelDerivedClass
设置为单例,仅可使用一次。将instance
函数添加到该类:
class ModelDerivedClass
{
...
ModelDerivedClass* instance() {
static ModelDerivedClass theInstance;
return &theInstance;
}
...
}
从C ++,您可以使用ModelDerivedClass::instance()
操作更改。
您还应该将它作为单例注册到QML:
qmlRegisterSingletonType<ModelDerivedClass>("DeviceListModel", 1, 0, "DeviceList",
[](QQmlEngine *eng, QJSEngine *js) -> QObject*
{
return ModelDerivedClass::instance();
});
但是在这种情况下,您对对象的生存期没有太多控制权,这可以说是不好的(可以在此主题上进行很多讨论)。因此,我建议您采用选项1。
主要要意识到的是,您的主线程是一个特殊线程,必须是访问和更改有关GUI状态的任何内容的唯一线程。有关Qt GUI和QML的大多数内容都是单线程的。
因此,您需要将更改从串行总线线程传递到主线程。这可以通过将插槽/信号从串行总线线程连接到主线程上的相应对象来完成。
Qt知道何时使用这样的连接跨越线程边界,并将其以某种方式发布到主线程,以确保以单线程方式对其进行处理。