Преобразование типов данных между 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_ENUM() или 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-массив и объект соответственно:
| 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. Компонент даты в полученном объекте Date не должен использоваться, так как он зависит от операционной системы. В частности, год (и месяц и день) установлены в ноль. Преобразование из JavaScript-объекта Date в QTime выполняется путём преобразования в QDateTime и последующим использованием QVariant для преобразования в QTime. Конечным результатом является то, что часть даты объекта Date игнорируется, но используется локальная временная зона, игнорируя любые проблемы с переходом на летнее время.
Типы последовательностей в JavaScript Array
Некоторые типы последовательностей C++ прозрачно поддерживаются в QML как типы JavaScript Array.
В частности, QML в настоящее время поддерживает:
QList<int>QList<qreal>QList<bool>-
QList<QString>иQStringList QList<QUrl>QVector<int>QVector<qreal>QVector<bool>
Эти типы последовательностей реализованы непосредственно в терминах базовых C++ последовательностей. Существует два способа экспонирования таких последовательностей в QML: в качестве свойства Q_PROPERTY заданного типа последовательности или как возвращаемый тип Q_INVOKABLE метода. Есть некоторые различия в способах их реализации, которые важно отметить.
Если последовательность экспонирована как Q_PROPERTY, доступ к любому значению в последовательности по индексу приведет к чтению данных последовательности из свойства объекта QObject, а затем к чтению. Аналогично, изменение любого значения в последовательности приведет к чтению данных последовательности, затем выполнению изменения и записи изменённой последовательности обратно в свойство объекта QObject.
Если последовательность возвращается из функции Q_INVOKABLE, доступ и изменение значительно проще, так как чтение или запись свойства объекта QObject не происходит; вместо этого данные C++ последовательности считываются и изменяются напрямую.
Другие типы последовательностей не поддерживаются прозрачно и вместо этого экземпляр любого другого типа последовательности будет передаваться между QML и C++ как непрозрачный QVariantList.
END_OF_DOCUMENT_MARKER ```Важно: Существуют некоторые незначительные различия между семантикой типов массивов последовательностей и стандартными типами массивов 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 |
| QVector<int> | целочисленное значение 0 |
| QVector<qreal> | вещественное значение 0.0 |
| QVector<bool> | булево значение false
|
Если вы хотите удалить элементы из последовательности, а не просто заменить их значениями по умолчанию, не используйте оператор удаления по индексу ("delete sequence[i]"), а используйте функцию splice ("sequence.splice(startIndex, deleteCount)").
Типы значений
Некоторые типы значений в Qt, такие как QPoint, представляются в JavaScript как объекты, имеющие те же свойства и функции, что и в C++ API. Такое же представление возможно для пользовательских типов значений C++. Для включения пользовательского типа значений в движок QML, объявление класса должно быть снабжено аннотацией Q_GADGET. Свойства, которые должны быть видимыми в представлении JavaScript, должны быть объявлены с помощью Q_PROPERTY. Аналогичным образом функции должны быть помечены как Q_INVOKABLE. Это также относится к основанным на QObject C++ API. Например, класс 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.
Типы перечислений в качестве параметров сигналов и методов
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.9/qtqml-cppintegration-data.html