Spec-Zone.ru › Qt 5.12

Преобразование типов данных между QML и C++

При обмене значениями данных между QML и C++, движок QML преобразует их к соответствующим типам данных, подходящим для использования в QML или C++. Это требует, чтобы данные имели тип, распознаваемый движком.

Движок QML предоставляет встроенную поддержку большого количества типов данных Qt C++. Кроме того, пользовательские типы C++ могут быть зарегистрированы в системе типов QML, чтобы сделать их доступными для движка.

На этой странице обсуждаются типы данных, поддерживаемые движком QML, и как они преобразуются между QML и C++.

Владение данными

При передаче данных из C++ в QML владение данными всегда остается у C++. Исключением из этого правила является случай, когда объект QObject возвращается из явного вызова метода C++: в этом случае движок QML принимает на себя владение объектом, если только владение объектом не было явно установлено в C++ путем вызова QQmlEngine::setObjectOwnership() со значением QQmlEngine::CppOwnership.

Кроме того, движок QML соблюдает обычную семантику владения родительскими объектами QObject объектов Qt C++, и никогда не удалит экземпляр QObject, у которого есть родитель.

Основные типы данных Qt

По умолчанию QML распознает следующие типы данных Qt, которые автоматически преобразуются в соответствующий базовый тип QML при передаче из C++ в QML и наоборот:

Тип Qt Базовый тип QML
bool bool
unsigned int, int int
double double
float, qreal real
QString string
QUrl url
QColor color
QFont font
QDateTime date
QPoint, QPointF point
QSize, QSizeF size
QRect, QRectF rect
QMatrix4x4 matrix4x4
QQuaternion quaternion
QVector2D, QVector3D, QVector4D vector2d, vector3d, vector4d
Перечисления, объявленные с помощью Q_ENUM() или Q_ENUMS() enumeration

Примечание: Классы, предоставляемые модулем Qt GUI, такие как QColor, QFont, QQuaternion и QMatrix4x4, доступны из QML только при включении модуля Qt Quick.

Для удобства многие из этих типов могут быть указаны в QML с помощью строковых значений или с помощью связанного метода, предоставляемого объектом QtQml::Qt. Например, свойство Image::sourceSize имеет тип size (что автоматически переводится в тип QSize) и может быть указано с помощью строкового значения, отформатированного как "widthxheight", или с помощью функции Qt.size():

Item {
    Image { sourceSize: "100x200" }
    Image { sourceSize: Qt.size(100, 200) }
}

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

Типы, производные от QObject

Любой класс, производный от QObject, может использоваться как тип для обмена данными между QML и C++, при условии, что класс был зарегистрирован в системе типов QML.

Движок позволяет регистрировать как создаваемые, так и не создаваемые типы. После регистрации класса как типа QML его можно использовать в качестве типа данных для обмена данными между QML и C++. Дополнительные сведения о регистрации типов см. в разделе Регистрация типов C++ в системе типов QML.

Преобразование между типами Qt и JavaScript

Движок QML поддерживает встроенное преобразование ряда типов Qt в соответствующие типы JavaScript и наоборот при передаче данных между QML и C++. Это позволяет использовать эти типы и получать их в C++ или JavaScript без необходимости реализации пользовательских типов, которые предоставляют доступ к значениям данных и их атрибутам.

(Обратите внимание, что среда JavaScript в QML изменяет прототипы собственных объектов JavaScript, включая те, что указаны в String, Date и Number, чтобы предоставить дополнительные возможности. Дополнительные сведения см. в разделе Среда выполнения JavaScript.)

QVariantList и QVariantMap в JavaScript массив и объект

Движок QML обеспечивает автоматическое преобразование между QVariantList и JavaScript массивами, а также между QVariantMap и JavaScript объектами.

Например, функция, определенная в QML ниже, ожидает два аргумента: массив и объект, и выводит их содержимое, используя стандартную JavaScript синтаксис для доступа к элементам массива и объекта. Код C++ ниже вызывает эту функцию, передавая QVariantList и QVariantMap, которые автоматически преобразуются в JavaScript массив и объект соответственно:

QML
// MyItem.qml
Item {
    function readValues(anArray, anObject) {
        for (var i=0; i<anArray.length; i++)
            console.log("Array item:", anArray[i])

        for (var prop in anObject) {
            console.log("Object item:", prop, "=", anObject[prop])
        }
    }
}
C++
// C++
QQuickView view(QUrl::fromLocalFile("MyItem.qml"));

QVariantList list;
list << 10 << QColor(Qt::green) << "bottles";

QVariantMap map;
map.insert("language", "QML");
map.insert("released", QDate(2010, 9, 21));

QMetaObject::invokeMethod(view.rootObject(), "readValues",
        Q_ARG(QVariant, QVariant::fromValue(list)),
        Q_ARG(QVariant, QVariant::fromValue(map)));

Это даст вывод, подобный этому:

Array item: 10
Array item: #00ff00
Array item: bottles
Object item: language = QML
Object item: released = Tue Sep 21 2010 00:00:00 GMT+1000 (EST)

Аналогично, если тип C++ использует QVariantList или QVariantMap для типа свойства или параметра метода, значение может быть создано как JavaScript массив или объект в QML, и автоматически преобразуется в QVariantList или QVariantMap при передаче в C++.

QDateTime в JavaScript Date

Движок QML предоставляет автоматическое преобразование между значениями QDateTime и объектами JavaScript Date.

Например, функция, определенная в QML ниже, ожидает объект JavaScript Date, а также возвращает новый объект Date с текущей датой и временем. Код C++ ниже вызывает эту функцию, передавая значение QDateTime, которое автоматически преобразуется движком в объект Date при передаче в функцию readDate(). В свою очередь, функция readDate() возвращает объект Date , который автоматически преобразуется в значение QDateTime при получении в C++:

QML
// MyItem.qml
Item {
    function readDate(dt) {
        console.log("The given date is:", dt.toUTCString());
        return new Date();
    }
}
C++
// C++
QQuickView view(QUrl::fromLocalFile("MyItem.qml"));

QDateTime dateTime = QDateTime::currentDateTime();
QDateTime retValue;

QMetaObject::invokeMethod(view.rootObject(), "readDate",
        Q_RETURN_ARG(QVariant, retValue),
        Q_ARG(QVariant, QVariant::fromValue(dateTime)));

qDebug() << "Value returned from readDate():" << retValue;

Аналогично, если тип C++ использует QDateTime для типа свойства или параметра метода, значение может быть создано как объект JavaScript Date в QML и автоматически преобразуется в значение QDateTime при передаче в C++.

QTime и JavaScript Date

Движок QML обеспечивает автоматическое преобразование значений QTime в JavaScript объекты Date. Поскольку значения QTime не содержат компонента даты, для преобразования создается компонент даты. Поэтому не следует полагаться на компонент даты полученного объекта Date.

Внутри преобразование объекта JavaScript Date в QTime выполняется путем преобразования в объект QDateTime и вызова метода time() этого объекта.

Последовательность типов в JavaScript массив

Определенные типы последовательностей C++ прозрачно поддерживаются в QML, чтобы вести себя как JavaScript типы Array.

В частности, QML в настоящее время поддерживает:

  • QList<int>
  • QList<qreal>
  • QList<bool>
  • QList<QString> и QStringList
  • QVector<QString>
  • std::vector<QString>
  • QList<QUrl>
  • QVector<QUrl>
  • std::vector<QUrl>
  • QVector<int>
  • QVector<qreal>
  • QVector<bool>
  • std::vector<int>
  • std::vector<qreal>
  • std::vector<bool>

Эти типы последовательностей реализованы непосредственно в терминах базовых C++ последовательностей. Существует два способа экспонирования таких последовательностей в QML: как свойство Q_PROPERTY данного типа последовательности или как возвращаемый тип вызываемого метода Q_INVOKABLE.

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

Если последовательность возвращается функцией Q_INVOKABLE, доступ и изменение намного дешевле, так как не происходит чтение или запись свойства объекта QObject; вместо этого данные последовательности C++ обращаются и изменяются непосредственно.

В обоих случаях (свойство Q_PROPERTY и возвращение от Q_INVOKABLE), элементы std::vector копируются. Эта копия может быть дорогостоящей операцией, поэтому следует использовать std::vector разумно.

END_OF_DOCUMENT_MARKER

Другие типы последовательностей не поддерживаются прозрачно, а вместо этого экземпляр любого другого типа последовательности будет передаваться между QML и C++ как непросветленный QVariantList.

Важно: Существуют некоторые незначительные различия между семантикой таких типов массивов последовательности и стандартных типов массивов JavaScript, которые возникают из-за использования типа хранения C++ в реализации. В частности, удаление элемента из массива приведет к замене этого элемента значением по умолчанию, а не значением Undefined. Аналогично, установка свойства length массива на значение, большее, чем его текущее значение, приведет к дополнению массива до указанной длины элементами по умолчанию вместо элементов Undefined. Наконец, классы контейнеров Qt поддерживают целые индексы со знаком (а не без знака); таким образом, попытка доступа к любому индексу, большему чем INT_MAX, завершится ошибкой.

Значения по умолчанию для каждого типа последовательности следующие:

QList<int> целое значение 0
QList<qreal> вещественное значение 0.0
QList<bool> логическое значение false
QList<QString> и QStringList пустая QString
QVector<QString> пустая QString
std::vector<QString> пустая QString
QList<QUrl> пустая QUrl
QVector<QUrl> пустая QUrl
std::vector<QUrl> пустая QUrl
QVector<int> целое значение 0
QVector<qreal> вещественное значение 0.0
QVector<bool> логическое значение false
std::vector<int> целое значение 0
std::vector<qreal> вещественное значение 0.0
std::vector<bool> логическое значение false

Если вы хотите удалить элементы из последовательности, а не просто заменить их значениями по умолчанию, не используйте оператор индексированного удаления ("delete sequence[i]"), а вместо этого используйте функцию splice ("sequence.splice(startIndex, deleteCount)").

QByteArray в JavaScript ArrayBuffer

Движок QML предоставляет автоматическое преобразование типа между значениями QByteArray и JavaScript ArrayBuffer объектами.

Типы значений

Некоторые типы значений в Qt, такие как QPoint, представлены в JavaScript в виде объектов, которые имеют те же свойства и функции, что и в API C++. Такое же представление возможно и с пользовательскими типами значений C++. Для включения пользовательского типа значения с движком QML объявление класса необходимо снабдить аннотацией Q_GADGET. Свойства, которые должны быть видны в представлении JavaScript, необходимо объявить с помощью Q_PROPERTY. Аналогично, функции необходимо пометить с помощью Q_INVOKABLE. Это относится и к API C++ на основе QObject. Например, класс Actor ниже аннотирован как gadget и имеет свойства:

class Actor
{
    Q_GADGET
    Q_PROPERTY(QString name READ name WRITE setName)
public:
    QString name() const { return m_name; }
    void setName(const QString &name) { m_name = name; }

private:
    QString m_name;
};

Q_DECLARE_METATYPE(Actor)

Типы перечислений

Для использования пользовательского перечисления в качестве типа данных, его класс должен быть зарегистрирован, а перечисление также должно быть объявлено с Q_ENUM() для регистрации в системе метаобъектов Qt. Например, класс Message ниже имеет перечисление Status:

class Message : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Status status READ status NOTIFY statusChanged)
public:
    enum Status {
        Ready,
        Loading,
        Error
    };
    Q_ENUM(Status)
    Status status() const;
signals:
    void statusChanged();
};

Если класс Message был зарегистрирован в системе типов QML, его перечисление Status можно использовать из QML:

Message {
     onStatusChanged: {
         if (status == Message.Ready)
             console.log("Message is loaded!")
     }
 }

Для использования перечисления в качестве типа флагов в QML, см. Q_FLAG().

Примечание: Имена значений перечисления должны начинаться с большой буквы, чтобы их можно было использовать из QML.

...
enum class Status {
          Ready,
          Loading,
          Error
}
Q_ENUM(Status)
...

Классы перечислений регистрируются в QML как свойства с областью видимости и без неё. Значение Ready будет зарегистрировано в Message.Status.Ready и Message.Ready .

При использовании классов перечислений может быть несколько перечислений с одинаковыми идентификаторами. Регистрация без области видимости будет перезаписана последним зарегистрированным перечислением. Для классов, содержащих такие конфликты имён, можно отключить регистрацию без области видимости, аннотировав свой класс специальным макросом Q_CLASSINFO. Используйте имя RegisterEnumClassesUnscoped со значением false для предотвращения объединения перечислений с областью видимости в одном пространстве имён.

class Message : public QObject
    {
        Q_OBJECT
        Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
        Q_ENUM(ScopedEnum)
        Q_ENUM(OtherValue)

    public:
        enum class ScopedEnum {
              Value1,
              Value2,
              OtherValue
        };
        enum class OtherValue {
              Value1,
              Value2
        };
    };

Типы перечислений в качестве параметров сигналов и методов

Сигналы и методы C++ с параметрами типа перечисления можно использовать из QML при условии, что перечисление и сигнал или метод объявлены в одном классе или что значение перечисления является одним из тех, что объявлены в пространстве имён Qt.

Кроме того, если сигнал C++ с параметром перечисления должен подключаться к функции QML с помощью функции connect(), тип перечисления должен быть зарегистрирован с помощью qRegisterMetaType().

Для сигналов QML значения перечислений можно передавать в качестве параметров сигнала, используя тип int:

Message {
    signal someOtherSignal(int statusValue)

    Component.onCompleted: {
        someOtherSignal(Message.Loading)
    }
}

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.12/qtqml-cppintegration-data.html

Spec-Zone.ru

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