Spec-Zone.ru › Qt 5.6

Преобразование типов данных между 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
QDate date
QPoint, QPointF point
QSize, QSizeF size
QRect, QRectF rect
QMatrix4x4 matrix4x4
QQuaternion quaternion
QVector2D, QVector3D, QVector4D vector2d, vector3d, vector4d
Перечисления, объявленные с Q_ENUMS() перечисление

Примечание: Классы, предоставляемые модулем 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 Array и Object

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

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

// MyItem.qml
Item {
    function readDate(dt) {
        console.log("The given date is:", dt.toUTCString());
        return new Date();
    }
}
// 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++.

Тип последовательности в JavaScript Array

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

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

  • QList<int>
  • QList<qreal>
  • QList<bool>
  • QList<QString> и QStringList
  • QList<QUrl>

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

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

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

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

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

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

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

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

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

Некоторые типы значений в 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_ENUMS(), чтобы зарегистрировать его в системе метаобъектов Qt. Например, класс Message ниже имеет перечисление Status.

class Message : public QObject
{
    Q_OBJECT
    Q_ENUMS(Status)
    Q_PROPERTY(Status status READ status NOTIFY statusChanged)
public:
    enum Status {
        Ready,
        Loading,
        Error
    };
    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.

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

Сигналы и методы 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/archives/qt-5.6/qtqml-cppintegration-data.html

Spec-Zone.ru

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