Spec-Zone.ru › Qt 5.9

Компилятор Qt удаленных объектов

Обзор REPC

Компилятор Replica Compiler (repc) генерирует заголовочные файлы QObject на основе файла определения API. Файл (называемый файлом "rep") использует специфический (текстовый) синтаксис для описания API. По соглашению, этим файлам присваивается расширение .rep, сокращение от Replica. При обработке этих файлов repc генерирует как заголовочные файлы Источника, так и Реплики.

Модуль Qt удалённых объектов также включает макросы qmake (REPC_SOURCE, REPC_REPLICA), которые можно добавить в файл проекта, чтобы автоматически запустить repc и добавить полученные файлы в список файлов, обрабатываемых Компилятором метаобъектов во время процесса сборки, упрощая использование Qt удалённых объектов в ваших проектах.

Хотя Qt удалённых объектов поддерживает совместное использование QObjects по сети (используя enableRemoting на стороне Источника и acquireDynamic на стороне Реплики), есть несколько преимуществ, связанных с использованием repc для определения ваших объектов. Во-первых, хотя DynamicReplicas полезны, с ними сложнее работать. API неизвестен до инициализации объекта, а использование API из C++ требует поиска строк через методы QMetaObject. Во-вторых, знание интерфейса во время компиляции позволяет найти любые проблемы во время компиляции, а не во время выполнения. В-третьих, формат rep поддерживает значения по умолчанию, что может быть полезно, если вы не можете гарантировать доступность Источника при создании Реплики.

См. документацию здесь для получения информации о использовании сгенерированных файлов в вашем коде. Здесь мы сосредоточимся на формате repc и опциях.

Формат файла rep

Формат файла rep — это простой язык предметной области (DSL) для описания интерфейса, поддерживаемого Qt удалёнными объектами (QtRO). Поскольку QtRO — это система на основе объектов, эти интерфейсы определяются API, доступными через объекты, то есть классы со свойствами, сигналами и слотами.

Тип класса

Каждый класс, определённый в файле rep, становится QObject в сгенерированных заголовочных файлах, с сгенерированным для вас описанным API.

Для определения класса используется ключевое слово class, за которым следует имя желаемого типа, а затем API заключён в квадратные скобки, как показано ниже

class MyType
{
    //PROP/SIGNAL/SLOT/ENUM declarations to define your API
};

PROP

Q_PROPERTY элементы создаются с помощью ключевого слова PROP в файле rep. Синтаксис — это ключевое слово PROP, за которым следует определение в кавычках, где определение представляет собой тип, имя и (необязательно) значение по умолчанию или атрибуты.

PROP(bool simpleBool)                // boolean named simpleBool
PROP(bool defaultFalseBool=false)    // boolean named defaultFalseBool, with false
                                     // as the default value

PROP(int lifeUniverseEverything=42)  // int value that defaults to 42
PROP(QByteArray myBinaryInfo)        // Qt types are fine, may need #include
                                     // additional headers in your rep file

PROP(QString name CONSTANT)          // Property with the CONSTANT attribute
PROP(QString setable READWRITE)      // Property with the READWRITE attribute
                                     // note: Properties default to READPUSH
                                     // (see description below)

PROP(SomeOtherType myCustomType)     // Custom types work. Needs #include for the
                                     // appropriate header for your type, make
                                     // sure your type is known to the metabject
                                     // system, and make sure it supports Queued
                                     // Connections (see Q_DECLARE_METATYPE and
                                     // qRegisterMetaType)

Дополнительную информацию о создании пользовательских типов можно найти здесь.

По умолчанию свойства будут иметь геттеры и «пуш»-слот, а также сигнал notify, который будет испускаться при изменении значения. Qt удалённых объектов требует сигнал notify на объекте Источника для запуска отправки обновлений прикреплённым Репликам. В более ранних версиях QtRO свойства по умолчанию были чтение/запись, то есть имели геттеры и сеттеры. Однако из-за асинхронной природы QtRO это иногда приводило к неинтуитивному поведению. Установка атрибута READWRITE на PROP обеспечит старое поведение (геттер и сеттер).

// In .rep file, old (setter) behavior
PROP(int myVal READWRITE)             // Old behavior with setMyVal(int myVal) method

// In code...  Assume myVal is initially set to 0 in Source
int originalValue = rep->myVal();     // Will be 0
rep->setMyVal(10);                    // Call setter, expecting a blocking/
                                      // non-asynchronous return

if (rep->myVal() == 10) ...           // Test will usually fail

Если необходимо заблокировать выполнение до изменения значения, требуется что-то вроде следующего.

// In .rep file, old (setter) behavior
PROP(int myVal READWRITE)             // Old behavior with setMyVal(int myVal) method

// In code...  Assume myVal is initially set to 0 in Source
bool originalValue = rep->myVal();    // Will be 0

// We can wait for the change using \l QSignalSpy
QSignalSpy spy(rep, SIGNAL(myValChanged(int)));

rep->setMyVal(10);                    // Call setter, expecting a blocking/
                                      // non-asynchronous return

spy.wait();                           // spy.wait() blocks until changed signal
                                      // is received
if (rep->myVal() == 10) ...           // Test will succeed assuming
                                      // 1. Source object is connected
                                      // 2. Nobody else (Source or other Replica)
                                      //    sets the myVal to something else (race
                                      //    condition)
// Rather than use QSignalSpy, the event-driven practice would be to connect the
// myValChanged notify signal to a Slot that responds to the changes.

Теперь QtRO по умолчанию использует READPUSH, что обеспечивает автоматически сгенерированный слот для запроса изменения свойства.

// In .rep file, defaults to READPUSH
PROP(bool myVal)                      // No setMyVal(int myVal) on Replica, has
                                      // pushMyVal(int myVal) instead

// In code...  Assume myVal is initially set to 0 in Source
bool originalValue = rep->myVal();    // Will be 0

// We can wait for the change using \l QSignalSpy
QSignalSpy spy(rep, SIGNAL(myValChanged(int)));

rep->pushMyVal(10);                   // Call push method, no expectation that change
                                      // is applied upon method completion.

// Some way of waiting for change to be received by the Replica is still necessary,
// but hopefully not a surprise with the new pushMyVal() Slot.
spy.wait();                           // spy.wait() blocks until changed signal
                                      // is received
if (rep->myVal() == 10) ...           // Test will succeed assuming
                                      // 1. Source object is connected
                                      // 2. Nobody else (Source or other Replica)
                                      //    set the myVal to something else (race
                                      //    condition)

Вы также можете использовать ключевые слова CONSTANT, READONLY, PERSISTED, READWRITE, или READPUSH в объявлении PROP, что влияет на способ реализации. READPUSH — значение по умолчанию, если не указано другое.

PROP(int lifeUniverseEverything=42 CONSTANT)
PROP(QString name READONLY)

Обратите внимание на некоторые нюансы. CONSTANT PROP имеет Q_PROPERTY, объявленный как CONSTANT на стороне ИСТОЧНИКА. Однако реплики не могут знать правильное значение до своей инициализации, что означает, что значение свойства должно быть разрешено изменяться во время инициализации. Для READONLY у Источника не будет ни сеттера, ни push-слота, а у реплики не будет сгенерированного push-слота. Добавление атрибута PERSISTED к PROP заставит PROP использовать экземпляр QRemoteObjectPersistedStore, установленный на узле (если таковой имеется), для сохранения/восстановления значений PROP.

SIGNAL

Сигналы создаются с помощью ключевого слова SIGNAL в файле rep.

Используйте объявление SIGNAL, за которым следует желаемая сигнатура в скобках. Возвращаемое значение void следует опустить.

SIGNAL(test())
SIGNAL(test(QString foo, int bar))
SIGNAL(test(QMap<QString,int> foo))
SIGNAL(test(const QString &foo))
SIGNAL(test(QString &foo))

Так же, как и в Qt очередных соединениях, параметры в сигналах, которые являются ссылками, будут скопированы при передаче репликам.

SLOT

Слоты создаются с помощью ключевого слова SLOT в файле rep.

Используйте объявление SLOT, за которым следует желаемая сигнатура в скобках. Значение возврата можно включить в объявление. Если значение возврата опущенно, в сгенерированных файлах будет использоваться void.

SLOT(test())
SLOT(void test(QString foo, int bar))
SLOT(test(QMap<QString,int> foo))
SLOT(test(QMap<QString,int> foo, QMap<QString,int> bar))
SLOT(test(QMap<QList<QString>,int> foo))
SLOT(test(const QString &foo))
SLOT(test(QString &foo))
SLOT(test(const QMap<QList<QString>,int> &foo))
SLOT(test(const QString &foo, int bar))

Так же, как и в Qt очередных соединениях и QtRO сигналах, параметры в слотах, которые являются ссылками, будут скопированы при передаче репликам.

ENUM

Перечисления (которые используют сочетание C++ перечисления и Q_ENUM Qt в QtRO) описываются с помощью ключевого слова ENUM.

ENUM MyEnum {Foo}
ENUM MyEnum {Foo, Bar}
ENUM MyEnum {Foo, Bar = -1}
ENUM MyEnum {Foo=-1, Bar}
ENUM MyEnum {Foo=0xf, Bar}
ENUM MyEnum {Foo=1, Bar=3, Bas=5}

Связанные темы: Тип ENUM, ключевое слово USE_ENUM

Тип POD

Plain Old Data (POD) — это термин, описывающий простое хранилище данных, подобное C++ структуре. Например, если у вас есть API для телефонной книги, вы можете использовать понятие "адрес" в его интерфейсе (где адрес может включать улицу, город, штат, страну и почтовый индекс). Вы можете использовать ключевое слово POD для определения таких объектов, которые затем могут использоваться в определениях PROP/SIGNAL/SLOT в определениях ваших классов.

Используйте объявление POD, за которым следует имя генерируемого типа, за которым следуют пары тип/имя, разделённые запятыми, где пары тип/имя заключены в скобки.

POD Foo(int bar)
POD Foo(int bar, double bas)
POD Foo(QMap<QString,int> bar)
POD Foo(QList<QString> bar)
POD Foo(QMap<QString,int> bar, QMap<double,int> bas)

Полный пример будет выглядеть так

POD Foo(QList<QString> bar)
class MyType
{
    SIGNAL(sendCustom(Foo foo));
};

Код, сгенерированный repc, создаёт класс Q_GADGET для каждого POD с соответствующими членами Q_PROPERTY для каждого определённого типа POD.

Тип ENUM

Часто проще и чище определить ENUM внутри класса (см. ENUM), но если вам нужен отдельный тип перечисления, использование ключевого слова ENUM вне определения класса может быть полезным. Это сгенерирует новый класс в ваших заголовочных файлах, который обрабатывает маршаллинг и т. д. Синтаксис идентичен ENUM, за исключением того, что объявление в этом случае не содержится в объявлении class.

Связанные темы: ENUM, ключевое слово USE_ENUM

Ключевое слово USE_ENUM

Ключевое слово USE_ENUM было реализовано до добавления автоматической генерации через ключевое слово ENUM. Оно сохранено для обратной совместимости.

Связанные темы: ENUM, Тип ENUM

Директивы

Файл rep определяет интерфейс, но интерфейсы часто требуют внешних элементов. Для поддержки этого repc будет включать все директивы (в одну строку) вверху сгенерированных файлов. Это позволяет, например, использовать директивы #include или #define, которые поддерживают необходимую логику или типы данных.

В настоящее время инструмент repc обрабатывает всё от символа "#" до конца строки и добавляет это в сгенерированные файлы. Поэтому многострочные #if/#else/#endif и многострочные макросы не поддерживаются.

Макросы файла проекта

REPC_REPLICA

...

REPC_SOURCE

...

QOBJECT_REPLICA

...

См. также QRemoteObjectPersistedStore.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.9/qtremoteobjects-repc.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API