Изменения флага Qt Quick / QML в C ++ возвращаются в интерфейс - PullRequest
0 голосов
/ 30 апреля 2020

Я знаком с Qt некоторое время назад, но я мог бы немного ориентироваться во взаимодействиях QML / QTQuick с C ++. Я чувствую, что упускаю что-то простое здесь, но я немного застрял.

Я разрабатываю встроенную систему, отображающую состояние распределенных коммутаторов, взаимодействующих по последовательной шине. Последовательная шина запускается как отдельный поток в C ++ (всегда был Qt) и автоматически опрашивает устройства в циклическом режиме для получения обновлений от устройств.

Посмотрев на это, я нашел довольно простой пример использования модели QAbstractList для передачи статуса через свойства QML из поддерживаемого C ++. https://www.youtube.com/watch?v=9BcAYDlpuT8&list=PLo12gBvZwC78nnrZHCBowKf36ZAi7iOLW&index=4&t=0s

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

Что я сделал до сих пор:

Регистрация модели:

qmlReisterType<ModelDerrivedClass>("DeviceListModel",1,0,"DeviceList")

Определение ролей:

   enum {
    OpenRole = Qt::UserRole,
    StatusRole
    }

Определение Ha sh таблица для модели

QHash<int,QByteArray> ModelDerrivedClass::roleNames() const
{
    QHash<int, QByteArray> names;
    names[OpenRole] = "openstatus";
    names[StatusRole] = "devicestatus";
    return names;
}

Создать простой список структур с правильной информацией, реализовать необходимые методы и т. д. c ... работает как шарм сверху вниз.

Как получить доступ к модели снизу вверх? Эти устройства будут обновлять состояние в соответствии с внешним вводом, о котором пользовательский интерфейс не должен знать, но эти события должны иметь возможность управлять внешним интерфейсом. Похоже, этот сценарий не учитывается.

Я также рассмотрел вопрос регистрации типа устройства с помощью QML, но не могу понять, как связать объект QML с объектом C ++, поэтому свойства READ / WRITE / NOTIFY работают с отдельными объектами QML в список. В этом сценарии я зарегистрировал бы OPEN и STATUS как свойства типа QML, которые можно было бы напрямую использовать в коде QML, но мне нужно было бы связать экземпляр объекта int C ++ с экземпляром объекта QML. Это то, над чем работает QAbstractListModel.

Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

0 голосов
/ 30 апреля 2020

Главное, что нужно понять, это то, что ваш основной поток является специальным потоком, который должен быть единственным потоком, который обращается к вашему состоянию GUI и изменяет его. Почти все, что касается Qt GUI и QML, является однопоточным.

Таким образом, вы захотите сообщить об изменении из потока последовательной шины в основной поток. Это можно сделать, подключив слот / сигнал из потока последовательной шины к соответствующему объекту в главном потоке.

Qt знает, когда вы пересекли границы потока с таким соединением, и опубликует его таким образом в основной поток, который гарантирует, что он обрабатывается однопоточным способом.

0 голосов
/ 30 апреля 2020

У вас есть два варианта, но я думаю, что первый лучше:

вариант 1: rootContext

Вы можете установить свойство для rootContext для QQMlEngine, который будет доступен в каждом файле QML, загруженном этим механизмом qml (см. Документы Qt ):

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 как singleton:

qmlRegisterSingletonType<ModelDerivedClass>("DeviceListModel", 1, 0, "DeviceList",
    [](QQmlEngine *eng, QJSEngine *js) -> QObject*
    {
        return ModelDerivedClass::instance();
    });

Но в этом случае вы не имеете большого контроля над временем жизни объекта, что, возможно, нехорошо (можно найти много дискуссий на эту тему). Поэтому я бы посоветовал воспользоваться вариантом 1.

...