Qt Quick / QML标志在C ++中更改回UI

问题描述 投票:0回答:2

我很早以前就对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适用的方法。

任何帮助将不胜感激。

c++ qt qml qtquick2
2个回答
0
投票

您有两种选择,但我认为第一种选择更好:

选项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。


0
投票

主要要意识到的是,您的主线程是一个特殊线程,必须是访问和更改有关GUI状态的任何内容的唯一线程。有关Qt GUI和QML的大多数内容都是单线程的。

因此,您需要将更改从串行总线线程传递到主线程。这可以通过将插槽/信号从串行总线线程连接到主线程上的相应对象来完成。

Qt知道何时使用这样的连接跨越线程边界,并将其以某种方式发布到主线程,以确保以单线程方式对其进行处理。

© www.soinside.com 2019 - 2024. All rights reserved.