Преобразование типов данных между 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