Data Type Conversion Between QML and C++

Qt 2017. 6. 11. 18:45

[원문] https://doc.qt.io/qt-5/qtqml-cppintegration-data.html


Data Type Conversion Between QML and C++

QML과 C++간에 데이터 값이 교환되면 QML 엔진에 의해 변환되어 QML 또는 C++에서 사용하기에 적합한 데이터 유형을 갖게됩니다. 이를 위해서는 교환 된 데이터가 엔진이 인식 할 수있는 유형이어야합니다.


QML 엔진은 다수의 Qt C++ 데이터 유형을 기본적으로 지원합니다. 또한 사용자 정의 C++ 유형을 QML 유형 시스템에 등록하여 엔진에서 사용할 수 있도록 할 수 있습니다.


이 페이지에서는 QML 엔진에서 지원하는 데이터 유형과 QML과 C++간에 변환되는 데이터 유형에 대해 설명합니다.


Data Ownership

데이터가 C++에서 QML로 전송되면 데이터의 소유권은 항상 C++로 유지됩니다. 이 규칙의 예외는 명시 적 C++ 메서드 호출에서 QObject가 반환 된 경우입니다.이 경우 QML 엔진은 개체의 소유권이 명시 적으로 C++로 유지되도록 설정되지 않은 한 QQmlEngine::QQmlEngine::CppOwnership이 지정된 setObjectOwnership().


또한 QML 엔진은 Qt C++ 개체의 일반적인 QObject 부모 소유권 의미를 따르며 부모가있는 QObject 인스턴스를 삭제하지 않습니다.

Basic Qt Data Types

기본적으로 QML은 다음과 같은 Qt 데이터 유형을 인식합니다.이 데이터 유형은 C++에서 QML로 또는 그 반대로 전달 될 때 자동으로 해당 QML 기본 유형으로 변환됩니다.

Qt TypeQML Basic Type
boolbool
unsigned int, intint
doubledouble
float, qrealreal
QStringstring
QUrlurl
QColorcolor
QFontfont
QDatedate
QPoint, QPointFpoint
QSize, QSizeFsize
QRect, QRectFrect
QMatrix4x4matrix4x4
QQuaternionquaternion
QVector2D, QVector3D, QVector4Dvector2d, vector3d, vector4d
Enums declared with Q_ENUM() or Q_ENUMS()enumeration

참고 : Qt GUI 모듈에서 제공하는 QColor, QFont, QQuaternion 및 QMatrix4x4와 같은 클래스는 Qt Quick 모듈이 포함 된 경우에만 QML에서 사용할 수 있습니다.


편의상 많은 유형의 문자열을 QML에서 문자열 값으로 지정하거나 QtQml::Qt 객체에서 제공하는 관련 메서드로 지정할 수 있습니다. 예를 들어 Image::sourceSize 속성은 size 유형 (자동으로 QSize 유형으로 변환 됨)이며 "widthxheight"또는 Qt.size() 함수로 포맷 된 문자열 값으로 지정할 수 있습니다.

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

자세한 내용은 QML 기본 유형에서 각 유형별 문서를 참조하십시오.

QObject-derived Types

모든 QObject 파생 클래스는 QML 유형 시스템에 클래스가 등록되어 있으면 QML과 C++ 간의 데이터 교환을위한 유형으로 사용할 수 있습니다.


엔진을 사용하면 인스턴스화 할 수있는 유형과 인스턴스화 할 수없는 유형을 모두 등록 할 수 있습니다. 클래스가 QML 유형으로 등록되면 QML과 C++간에 데이터를 교환하기위한 데이터 유형으로 사용할 수 있습니다. 형식 등록에 대한 자세한 내용은 QML 유형 시스템에 C++ 유형 등록을 참조하십시오.


Conversion Between Qt and JavaScript Types


QML 엔진에는 QML과 C++간에 데이터를 전송할 때 여러 가지 Qt 유형을 관련 JavaScript 유형으로 변환하거나 그 반대로 지원하는 내장형 지원이 있습니다. 이렇게하면 데이터 유형과 해당 속성에 대한 액세스를 제공하는 사용자 정의 유형을 구현할 필요없이 이러한 유형을 사용하고 C++ 또는 JavaScript로 수신 할 수 있습니다.


(QML의 JavaScript 환경은 추가 기능을 제공하기 위해 String, Date 및 Number의 프로토 타입을 포함하여 기본 JavaScript 객체 프로토 타입을 수정합니다. 자세한 내용은 JavaScript 호스트 환경을 참조하십시오.)


QVariantList and QVariantMap to JavaScript Array and 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 유형을 사용하는 경우이 값은 QML의 JavaScript 배열 또는 객체로 생성 될 수 있으며 C++로 전달 될 때 자동으로 QVariantList 또는 QVariantMap으로 변환됩니다.


QDateTime to JavaScript Date


QML 엔진은 QDateTime 값과 JavaScript Date 객체간에 자동 유형 변환을 제공합니다.


예를 들어, 아래 QML에서 정의 된 함수는 JavaScript Date 객체를 예상하고 현재 날짜와 시간이 포함 된 새 Date 객체를 반환합니다. 아래의 C++ 코드는이 함수를 호출하여 readDate() 함수에 전달 될 때 엔진에 의해 자동으로 Date 객체로 변환되는 QDateTime 값을 전달합니다. ReadDate() 함수는 C++에서 수신 될 때 자동으로 QDateTime 값으로 변환되는 Date 객체를 반환합니다.

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을 사용하는 경우 값은 QML에서 JavaScript Date 객체로 생성 될 수 있으며 C++에 전달 될 때 자동으로 QDateTime 값으로 변환됩니다.


QTime to JavaScript Date


QML 엔진은 QTime 값에서 JavaScript Date 객체로의 자동 유형 변환을 제공합니다. 결과로 생성 된 Date 객체의 날짜 구성 요소는 운영 체제에 의존하므로 의존해서는 안됩니다. 특히 연도 (및 월과 일)는 0으로 설정됩니다. JavaScript Date 객체에서 QTime으로의 변환은 QDateTime으로 변환 한 다음 QVariant를 사용하여 QTime으로 변환하여 수행됩니다. 결과적으로 Date 개체의 날짜 부분은 무시되지만 DST의 복잡성을 무시하고 현지 표준 시간대가 사용됩니다.


Sequence Type to JavaScript Array

특정 C++ 시퀀스 유형은 QML에서 JavaScript Array 유형으로 투명하게 지원됩니다.


특히, QML은 현재 다음을 지원합니다.


  • QList<int>
  • QList<qreal>
  • QList<bool>
  • QList<QString> and 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로 전달됩니다.


중요 : 이러한 배열 배열 유형의 의미와 구현시 C++ 저장소 유형의 사용으로 인해 발생하는 기본 JavaScript Array 유형에는 약간의 차이가 있습니다. 특히 배열에서 요소를 삭제하면 정의되지 않은 값 대신 해당 요소를 대체하는 기본 생성 값이됩니다. 마찬가지로 Array의 length 속성을 현재 값보다 큰 값으로 설정하면 배열이 정의되지 않은 요소가 아닌 기본 생성 요소로 지정된 길이만큼 채워집니다. 마지막으로 Qt 컨테이너 클래스는 부호없는 (서명되지 않은) 정수 인덱스를 지원합니다. 따라서 INT_MAX보다 큰 인덱스에 액세스하려고하면 실패합니다.


각 시퀀스 유형에 대한 기본값으로 구성된 값은 다음과 같습니다.

QList<int>integer value 0
QList<qreal>real value 0.0
QList<bool>boolean value false
QList<QString> and QStringListempty QString
QList<QUrl>empty QUrl
QVector<int>integer value 0
QVector<qreal>real value 0.0
QVector<bool>boolean value false

시퀀스를 단순히 기본 구성 값으로 대체하는 대신 시퀀스에서 요소를 제거하려면 인덱스 삭제 연산자 ("delete sequence [i]")를 사용하지 말고 splice 함수 ( "sequence.splice(startIndex, deleteCount)").


Value types

QPoint와 같은 Qt의 일부 값 유형은 JavaScript에서 C++ API와 같은 속성 및 기능을 가진 객체로 표시됩니다. 사용자 정의 C++ 값 유형에서도 동일한 표현이 가능합니다. QML 엔진에서 사용자 정의 값 유형을 사용하려면 클래스 선언에 Q_GADGET 주석을 추가해야합니다. JavaScript 표현에서 볼 수있는 속성은 Q_PROPERTY로 선언해야합니다. 마찬가지로 함수는 Q_INVOKABLE로 표시되어야합니다. 이것은 QObject 기반 C++ API와 동일합니다. 예를 들어, 아래 Actor 클래스는 가제트로 주석 처리되고 속성을가집니다.

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)

Enumeration Types

커스텀 열거 형을 데이터 타입으로 사용하기 위해서는 Qt의 메타 오브젝트 시스템에 그것을 등록하기 위해 그 클래스가 등록되어야하고 열거 형을 Q_ENUM()으로 선언해야한다. 예를 들어 아래의 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 타입 시스템에 등록하면 QML에서 Status 열거 형을 사용할 수 있습니다.

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

enum을 QML의 플래그 유형으로 사용하려면 Q_FLAG()를 참조하십시오.


참고 : 열거 형 값의 이름은 QML에서 액세스 할 수 있도록 대문자로 시작해야합니다.


Enumeration Types as Signal and Method Parameters

열거 형과 매개 변수가있는 C++ 신호 및 메서드는 QML에서 사용할 수 있습니다. 단, 열거 형과 신호 또는 메서드는 모두 같은 클래스 내에서 선언되거나 열거 형 값은 Qt 네임 스페이스에서 선언 된 값 중 하나입니다.


또한 enum 매개 변수가있는 C++ 신호를 connect() 함수를 사용하여 QML 함수에 연결할 수 있으면 qRegisterMetaType()을 사용하여 열거 형을 등록해야합니다.


QML 신호의 경우 enum 값은 int 유형을 사용하여 신호 매개 변수로 전달 될 수 있습니다.

Message {
    signal someOtherSignal(int statusValue)

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


: