Spec-Zone.ru › Qt 5.9

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

Spec-Zone.ru

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