QML과 C++ 간의 데이터 유형 변환

QML과 C++ 간에 데이터 값을 교환할 때, QML 엔진은 QML 또는 C++에서 사용하기에 적합한 올바른 데이터 유형으로 변환합니다. 이를 위해서는 교환된 데이터가 엔진에서 인식할 수 있는 유형이어야 합니다.

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

C++ 및 다양한 QML 통합 방법에 대한 자세한 내용은 C++ 및 QML 통합 개요 페이지를 참조하십시오.

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

데이터 소유권

데이터가 C++에서 QML로 전송될 때 데이터의 소유권은 항상 C++에 남아 있습니다. 이 규칙의 예외는 명시적 C++ 메서드 호출에서 QObject 이 반환되는 경우입니다. 이 경우, QQmlEngine::CppOwnership을 지정하여 QQmlEngine::setObjectOwnership()을 호출하여 객체의 소유권이 C++에 유지되도록 명시적으로 설정되지 않은 한, QML 엔진이 객체의 소유권을 가져옵니다.

또한 QML 엔진은 Qt C++ 객체의 일반적인 QObject 부모 소유권 시맨틱을 존중하며 부모가 있는 QObject 인스턴스는 절대 삭제하지 않습니다.

기본 Qt 데이터 유형

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

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

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

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

자세한 내용은 QML 값 유형 아래의 각 개별 유형에 대한 설명서를 참조하세요.

QObject 파생 유형

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

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

Qt와 JavaScript 타입 간 변환

QML 엔진은 QML과 C++ 간에 데이터를 전송할 때 여러 Qt 유형을 관련 JavaScript 유형으로 변환하거나 그 반대로 변환하는 기능을 기본적으로 지원합니다. 따라서 데이터 값과 그 속성에 대한 액세스를 제공하는 사용자 정의 유형을 구현할 필요 없이 이러한 유형을 사용하여 C++ 또는 JavaScript로 수신할 수 있습니다.

(QML의 JavaScript 환경은 String, DateNumber 의 프로토타입을 비롯한 기본 JavaScript 객체 프로토타입을 수정하여 추가 기능을 제공한다는 점에 유의하세요. 자세한 내용은 JavaScript 호스트 환경을 참조하세요.)

QVariantList 및 QVariantMap을 JavaScript 배열형 및 객체형으로 변환

QML 엔진은 QVariantList 와 JavaScript 배열형, QVariantMap 와 JavaScript 객체 간의 자동 유형 변환을 제공합니다.

배열 유사형은 ECMAScript 용어로 배열처럼 사용되는 객체입니다. QVariantList (및 기타 C++ 순차 컨테이너)에서 변환하여 생성된 배열-like는 그뿐만 아니라 일반적인 배열 메서드를 제공하고 길이 속성을 자동으로 동기화합니다. 모든 실용적인 용도로 자바스크립트 배열처럼 사용할 수 있습니다. 하지만 Array.isArray() 메서드는 여전히 거짓을 반환합니다.

예를 들어 아래 QML에 정의된 함수는 배열과 객체라는 두 개의 인수를 예상하고 배열 및 객체 항목 액세스를 위한 표준 JavaScript 구문을 사용하여 그 내용을 인쇄합니다. 아래 C++ 코드는 이 함수를 호출하여 QVariantListQVariantMap 을 전달하며, 이 값은 각각 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 로 변환됩니다.

Qt 6.5부터는 C++ 타입의 QVariantList 프로퍼티를 QML 코드로 대신 변경할 수 있습니다. 하지만 C++ 타입의 QVariantMap 프로퍼티에는 해당되지 않는다는 점에 유의하세요. 이는 값으로 저장되며 QML 코드로 제자리에서 변경할 수 없습니다. 전체 맵만 바꿀 수 있고 맵의 내용은 조작할 수 없습니다. m 속성이 QVariantMap 인 경우 다음 코드는 작동하지 않습니다:

MyMapExposingItem {
   m: ({ one: 1 })
   Component.onCompleted: m.ten = 10
}

다음 코드는 작동합니다:

MyMapExposingItem {
   m: ({ one: 1 })
   Component.onCompleted: m = { one: 1, ten: 10 }
}

QDateTime을 자바스크립트 날짜로

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

예를 들어, 아래 QML에 정의된 함수는 JavaScript Date 객체를 예상하고 현재 날짜와 시간이 포함된 새 Date 객체를 반환합니다. 아래 C++ 코드는 이 함수를 호출하여 QDateTime 값을 readDate() 함수에 전달할 때 엔진에서 Date 객체로 자동 변환된 값을 전달합니다. 차례로 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 값으로 변환됩니다.

참고: 월 번호의 차이에 주의하세요: 자바스크립트는 1월을 0~11로, 12월을 1~12로 번호 매기는 Qt의 1월 번호 매기기에서 1씩 떨어져 있습니다.

참고: JavaScript에서 문자열을 Date 객체의 값으로 사용할 때 시간 필드가 없는 문자열(즉, 단순 날짜)은 현지 시간 시작을 사용하는 new Date(y, m, d) 과 달리 해당 날짜의 UTC 시작으로 해석된다는 점에 유의하세요. 자바스크립트에서 Date 객체를 구성하는 다른 대부분의 방법은 이름에 UTC가 포함된 메서드를 사용하지 않는 한 현지 시간을 생성합니다. 프로그램이 UTC보다 늦은 지역(명목상으로는 자오선의 서쪽)에서 실행되는 경우 날짜 전용 문자열을 사용하면 getDate() 이 문자열의 날짜 숫자보다 하나 적은 getHours() 값이 큰 Date 객체가 생성됩니다. 이러한 메서드의 UTC 변형인 getUTCDate()getUTCHours() 은 이러한 Date 객체에 대해 예상되는 결과를 제공합니다. 다음 섹션도 참조하세요.

QDate 및 JavaScript 날짜

QML 엔진은 날짜를 UTC 시작 시간으로 표시하여 QDate 와 자바스크립트 Date 유형 간에 자동으로 변환합니다. 날짜는 QDateTime 을 통해 date() 메서드를 선택하여 UTC 형식의 날짜가 다음 날의 시작과 일치하지 않는 한 현지 시간 형식을 사용하여 QDate 으로 다시 매핑되며, 이 경우 UTC 형식이 사용됩니다.

이 약간 특이한 배열은 JavaScript가 날짜 전용 문자열에서 Date 객체를 구성할 때 UTC 날짜 시작을 사용하지만 new Date(y, m, d) 은 표시된 날짜의 현지 시간 시작을 사용한다는 사실에 대한 해결 방법입니다(이전 섹션의 마지막에 설명된 참고 사항 참조).

따라서 QDate 속성이나 매개변수가 QML에 노출된 경우 해당 값을 읽을 때 주의해야 합니다. Date.getUTCFullYear(), Date.getUTCMonth()Date.getUTCDate() 메서드는 이름에 UTC가 없는 해당 메서드보다 사용자가 기대하는 결과를 제공할 가능성이 더 높습니다.

따라서 일반적으로 QDateTime 프로퍼티를 사용하는 것이 더 강력합니다. 이렇게 하면 QDateTime 쪽에서 날짜(및 시간)를 UTC 또는 현지 시간으로 지정할지 여부를 제어할 수 있으며, 자바스크립트 코드가 동일한 표준으로 작동하도록 작성되어 있다면 문제를 피할 수 있습니다.

QTime 및 JavaScript 날짜

QML 엔진은 QTime 값에서 JavaScript Date 객체로 자동 유형 변환을 제공합니다. QTime 값에는 날짜 컴포넌트가 포함되어 있지 않으므로 변환을 위해서만 날짜 컴포넌트가 생성됩니다. 따라서 결과물인 Date 객체의 날짜 구성 요소에 의존해서는 안 됩니다.

내부적으로 JavaScript Date 객체에서 QTime 객체로 변환하는 작업은 QDateTime 객체로 변환(현지 시간 사용)하고 time() 메서드를 호출하여 수행됩니다.

시퀀스 유형을 자바스크립트 배열로 변환

시퀀스 타입에 대한 일반적인 설명은 QML 시퀀스 타입 을 참조하세요. QtQml module 에는 사용할 수 있는 몇 가지 시퀀스 유형이 포함되어 있습니다.

QJSEngine::newArray()을 사용하여 QJSValue 을 작성하여 목록과 같은 데이터 구조를 만들 수도 있습니다. 이러한 JavaScript 배열은 QML과 C++ 간에 전달할 때 변환이 필요하지 않습니다. C++에서 JavaScript 배열을 조작하는 방법에 대한 자세한 내용은 QJSValue#Working With Arrays 을 참조하세요.

QByteArray를 자바스크립트 배열 버퍼로 변환하기

QML 엔진은 QByteArray 값과 JavaScript ArrayBuffer 객체 간의 자동 유형 변환을 제공합니다.

값 유형

QPoint 같은 Qt의 일부 값 유형은 자바스크립트에서 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)

일반적인 패턴은 가젯 클래스를 프로퍼티의 유형으로 사용하거나 가젯을 신호 인수로 사용하는 것입니다. 이러한 경우 가젯 인스턴스는 값 유형이기 때문에 C++와 QML 간에 값으로 전달됩니다. QML 코드가 가젯 프로퍼티의 프로퍼티를 변경하면 전체 가젯이 다시 생성되어 C++ 프로퍼티 설정자에게 다시 전달됩니다. Qt 5에서 가젯 유형은 QML에서 직접 선언하여 인스턴스화할 수 없습니다. 반면 QObject 인스턴스는 선언할 수 있으며 QObject 인스턴스는 항상 C++에서 QML로 포인터로 전달됩니다.

열거형

사용자 정의 열거형을 데이터 유형으로 사용하려면 해당 클래스를 등록하고 열거형도 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에서 열거형을 flags 유형으로 사용하려면 Q_FLAG()를 참조하세요.

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

...
enum class Status {
          Ready,
          Loading,
          Error
}
Q_ENUM(Status)
...

열거형 클래스는 QML에서 범위 지정 및 범위 지정되지 않은 프로퍼티로 등록됩니다. Ready 값은 Message.Status.ReadyMessage.Ready 에 등록됩니다.

열거형 클래스를 사용할 때 동일한 식별자를 사용하는 열거형이 여러 개 있을 수 있습니다. 범위가 지정되지 않은 등록은 마지막으로 등록된 열거형에 의해 덮어씌워집니다. 이러한 이름 충돌이 있는 클래스의 경우 특수 Q_CLASSINFO 매크로를 사용하여 클래스에 주석을 달아 범위 지정 해제 등록을 비활성화할 수 있습니다. 범위 지정 열거형이 같은 이름 공간에 병합되는 것을 방지하려면 false 값과 함께 RegisterEnumClassesUnscoped 이름을 사용하세요.

class Message : public QObject
    {
        Q_OBJECT
        Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
        Q_ENUM(ScopedEnum)
        Q_ENUM(OtherValue)

    public:
        enum class ScopedEnum {
              Value1,
              Value2,
              OtherValue
        };
        enum class OtherValue {
              Value1,
              Value2
        };
    };

관련 유형의 열거형은 일반적으로 관련 유형의 스코프에 등록됩니다. 예를 들어 Q_PROPERTY 선언에 다른 유형의 열거 형을 사용하면 해당 유형의 모든 열거 형이 QML에서 사용할 수 있게 됩니다. 이는 일반적으로 기능보다는 책임에 가깝습니다. 이를 방지하려면 특별한 Q_CLASSINFO 매크로를 사용하여 클래스에 주석을 추가하세요. RegisterEnumsFromRelatedTypes 이름과 false 값을 사용하여 관련 유형의 열거 형이 이 유형에 등록되지 않도록 합니다.

QML에서 사용하려는 열거 형을 다른 유형에 주입하기 위해 해당 열거 형에 의존하지 말고 QML_ELEMENT 또는 QML_NAMED_ELEMENT 을 사용하여 열거 형을 둘러싸는 유형을 명시적으로 등록해야 합니다.

class OtherType : public QObject
{
    Q_OBJECT
    QML_ELEMENT

public:
    enum SomeEnum { A, B, C };
    Q_ENUM(SomeEnum)

    enum AnotherEnum { D, E, F };
    Q_ENUM(AnotherEnum)
};

class Message : public QObject
{
    Q_OBJECT
    QML_ELEMENT

    // This would usually cause all enums from OtherType to be registered
    // as members of Message ...
    Q_PROPERTY(OtherType::SomeEnum someEnum READ someEnum CONSTANT)

    // ... but this way it doesn't.
    Q_CLASSINFO("RegisterEnumsFromRelatedTypes", "false")

public:
    OtherType::SomeEnum someEnum() const { return OtherType::B; }
};

중요한 차이점은 QML에서 열거형에 대한 범위입니다. 관련 클래스의 열거 형이 자동으로 등록되는 경우 범위는 해당 열거 형을 가져오는 유형입니다. 위의 경우 추가 Q_CLASSINFO 가 없으면 예를 들어 Message.A 을 사용합니다. 열거형을 포함하는 C++ 유형이 명시적으로 등록되어 있고 관련 유형의 열거형 등록이 억제된 경우, 열거형을 포함하는 C++ 유형의 QML 유형이 모든 열거형의 범위가 됩니다. QML에서 Message.A 대신 OtherType.A 을 사용하는 것입니다.

QML_FOREIGN 을 사용하여 수정할 수 없는 유형을 등록할 수 있습니다. 또한 QML_FOREIGN_NAMESPACE 을 사용하여 동일한 C++ 유형이 QML 값 유형으로도 등록되어 있는 경우에도 C++ 유형의 열거자를 대문자 이름의 QML 네임스페이스에 등록할 수 있습니다.

신호 및 메서드 매개변수로서의 열거형 유형

열거형 매개변수가 있는 C++ 신호 및 메서드는 열거형과 신호 또는 메서드가 모두 동일한 클래스 내에서 선언되거나 열거값이 Qt Namespace 에 선언된 것 중 하나인 경우 QML에서 사용할 수 있습니다.

또한 열거형 매개변수가 있는 C++ 신호가 connect() 함수를 사용하여 QML 함수에 연결되어야 하는 경우, 열거형 유형은 qRegisterMetaType()를 사용하여 등록해야 합니다.

QML 신호의 경우 열거형 값은 int 유형을 사용하여 신호 매개변수로 전달할 수 있습니다:

Message {
    signal someOtherSignal(int statusValue)

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

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.