프로퍼티 시스템
Qt는 일부 컴파일러 벤더가 제공하는 것과 유사한 정교한 프로퍼티 시스템을 제공합니다. 그러나 컴파일러와 플랫폼에 독립적인 라이브러리인 Qt는 __property
또는 [property]
과 같은 비표준 컴파일러 기능에 의존하지 않습니다. Qt 솔루션은 Qt가 지원하는 모든 플랫폼에서 모든 표준 C++ 컴파일러와 함께 작동합니다. 또한 신호와 슬롯을 통한 객체 간 통신을 제공하는 메타 객체 시스템을 기반으로 합니다.
프로퍼티 선언을 위한 요구 사항
프로퍼티를 선언하려면 QObject 을 상속하는 클래스에서 Q_PROPERTY() 매크로를 사용합니다.
Q_PROPERTY(type name (READ getFunction [WRITE setFunction] | MEMBER memberName [(READ getFunction | WRITE setFunction)]) [RESET resetFunction] [NOTIFY notifySignal] [REVISION int | REVISION(int[, int])] [DESIGNABLE bool] [SCRIPTABLE bool] [STORED bool] [USER bool] [BINDABLE bindableProperty] [CONSTANT] [FINAL] [REQUIRED])
다음은 QWidget 클래스에서 가져온 프로퍼티 선언의 일반적인 예시입니다.
Q_PROPERTY(bool focus READ hasFocus) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)
다음은 MEMBER
키워드를 사용하여 멤버 변수를 Qt XML 프로퍼티로 내보내는 방법을 보여주는 예제입니다. QML 프로퍼티 바인딩을 허용하려면 NOTIFY
시그널을 지정해야 합니다.
Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged) Q_PROPERTY(qreal spacing MEMBER m_spacing NOTIFY spacingChanged) Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged) ... signals: void colorChanged(); void spacingChanged(); void textChanged(const QString &newText); private: QColor m_color; qreal m_spacing; QString m_text;
프로퍼티는 클래스 데이터 멤버처럼 동작하지만 메타 객체 시스템을 통해 액세스할 수 있는 추가 기능이 있습니다.
MEMBER
변수가 지정되지 않은 경우READ
접근자 함수가 필요합니다. 이 함수는 속성 값을 읽기 위한 것입니다. 이 용도로는 const 함수를 사용하는 것이 이상적이며, 이 함수는 속성의 유형 또는 해당 유형에 대한 const 참조를 반환해야 합니다(예: QWidget::focus 는READ
함수, QWidget::hasFocus()가 있는 읽기 전용 속성입니다).BINDABLE
가 지정된 경우READ default
을 작성하여BINDABLE
에서READ
접근자를 생성할 수 있습니다.WRITE
접근자 함수는 선택 사항입니다. 속성 값을 설정하기 위한 것입니다. 이 함수는 무효를 반환해야 하며 속성 유형 또는 해당 유형에 대한 포인터 또는 참조 중 정확히 하나의 인수를 받아야 합니다(예: QWidget::enabled 에는WRITE
함수 QWidget::setEnabled()가 있습니다. 읽기 전용 속성에는WRITE
함수가 필요하지 않습니다. 예: QWidget::focus 에는WRITE
함수가 없습니다.BINDABLE
와WRITE default
을 모두 지정하면BINDABLE
에서WRITE
접근자가 생성됩니다. 생성된WRITE
접근자는NOTIFY
로 선언된 신호를 명시적으로 방출하지 않습니다. 예를 들어 Q_OBJECT_BINDABLE_PROPERTY 을 사용하여BINDABLE
에 변경 핸들러로 신호를 등록해야 합니다.READ
접근자 함수가 지정되지 않은 경우MEMBER
변수 연결이 필요합니다. 이렇게 하면READ
및WRITE
접근자 함수를 만들지 않고도 지정된 멤버 변수를 읽고 쓸 수 있습니다. 변수 액세스를 제어해야 하는 경우MEMBER
변수 연결 외에READ
또는WRITE
접근자 함수를 사용할 수 있습니다(둘 다 사용할 수는 없음).RESET
함수는 선택 사항입니다. 예를 들어 QWidget::cursor 에는 일반적인READ
및WRITE
함수, QWidget::cursor() 및 QWidget::setCursor()가 있으며, QWidget::setCursor()를 호출하지 않으면 컨텍스트별 커서로 재설정될 수 있으므로RESET
함수, QWidget::unsetCursor()도 있습니다.RESET
함수는 무효를 반환하고 매개 변수를 받지 않아야 합니다.NOTIFY
신호는 선택 사항입니다. 정의된 경우 해당 클래스에서 속성 값이 변경될 때마다 발생하는 기존 신호 하나를 지정해야 합니다.MEMBER
변수에 대한NOTIFY
신호는 0 또는 하나의 매개 변수를 취해야 하며, 이 매개 변수는 속성과 동일한 유형이어야 합니다. 매개변수는 프로퍼티의 새 값을 받습니다.NOTIFY
신호는 예를 들어 QML에서 바인딩이 불필요하게 재평가되는 것을 방지하기 위해 속성이 실제로 변경된 경우에만 발생해야 합니다. 이 신호는 Qt API(QObject::setProperty, QMetaProperty, 등)를 통해 프로퍼티가 변경될 때 자동으로 발생하지만, 멤버가 직접 변경될 때는 발생하지 않습니다.REVISION
번호 또는REVISION()
매크로는 선택 사항입니다. 포함하면 API의 특정 개정판에서 사용할 프로퍼티와 해당 알림 신호를 정의합니다(일반적으로 QML에 노출하기 위해). 포함되지 않으면 기본값은 0입니다.DESIGNABLE
속성은 프로퍼티를 GUI 디자인 도구의 프로퍼티 편집기에 표시할지 여부를 나타냅니다(예 Qt Widgets Designer). 대부분의 속성은DESIGNABLE
(기본값은 true)입니다. 유효한 값은 참과 거짓입니다.SCRIPTABLE
속성은 스크립팅 엔진에서 이 속성에 액세스할 수 있는지 여부를 나타냅니다(기본값은 true). 유효한 값은 참과 거짓입니다.STORED
속성은 속성을 자체적으로 존재하는 것으로 간주할지 아니면 다른 값에 따라 달라지는 것으로 간주할지를 나타냅니다. 또한 객체의 상태를 저장할 때 속성 값을 저장해야 하는지 여부를 나타냅니다. 대부분의 속성은STORED
(기본값 참)이지만, 예를 들어 QWidget::minimumWidth()의 값은 QWidget::minimumSize()의 너비 구성 요소인 QSize 에서 가져온 것이므로STORED
거짓입니다.USER
속성은 해당 속성이 클래스의 사용자 표시 속성으로 지정되었는지 또는 사용자가 편집할 수 있는 속성으로 지정되었는지를 나타냅니다. 일반적으로 클래스당USER
속성은 하나만 있습니다(기본값은 거짓). 예를 들어 QAbstractButton::checked 은 (체크 가능) 버튼에 대한 사용자 편집 가능 속성입니다. QItemDelegate 는 위젯의USER
속성을 가져오고 설정합니다.BINDABLE bindableProperty
속성은 속성이 바인딩을 지원하며 메타 객체 시스템(QMetaProperty)을 통해 이 속성에 대한 바인딩을 설정하고 검사할 수 있음을 나타냅니다.bindableProperty
는 QBindable<T> 타입의 클래스 멤버의 이름을 지정하며, 여기서 T는 속성 유형입니다. 이 어트리뷰트는 Qt 6.0에 도입되었습니다.CONSTANT
속성이 있으면 속성 값이 상수임을 나타냅니다. 주어진 객체 인스턴스에 대해 상수 프로퍼티의 READ 메서드는 호출될 때마다 동일한 값을 반환해야 합니다. 이 상수 값은 객체의 인스턴스마다 다를 수 있습니다. 상수 프로퍼티에는 WRITE 메서드나 NOTIFY 신호를 가질 수 없습니다.FINAL
속성이 있으면 해당 프로퍼티가 파생 클래스에 의해 재정의되지 않음을 나타냅니다. 이는 경우에 따라 성능 최적화를 위해 사용될 수 있지만 moc에 의해 강제되지는 않습니다.FINAL
속성을 재정의하지 않도록 주의해야 합니다.REQUIRED
속성이 있으면 해당 속성은 클래스 사용자가 설정해야 함을 나타냅니다. 이는 moc에 의해 강제되지 않으며 주로 QML에 노출된 클래스에 유용합니다. QML에서 REQUIRED 속성이 있는 클래스는 모든 REQUIRED 속성이 설정되지 않으면 인스턴스화할 수 없습니다.
READ
, WRITE
, RESET
함수는 상속할 수 있습니다. 또한 가상이 될 수도 있습니다. 다중 상속이 사용되는 클래스에서 상속되는 경우 첫 번째로 상속된 클래스에서 상속되어야 합니다.
속성 유형은 QVariant 에서 지원하는 모든 유형이거나 사용자 정의 유형일 수 있습니다. 이 예제에서 QDate 클래스는 사용자 정의 유형으로 간주됩니다.
Q_PROPERTY(QDate date READ getDate WRITE setDate)
QDate 은 사용자 정의 유형이므로 속성 선언에 <QDate>
헤더 파일을 포함해야 합니다.
역사적인 이유로 속성 유형인 QMap 및 QList 은 QVariantMap 및 QVariantList 과 동의어입니다.
메타 객체 시스템으로 속성 읽기 및 쓰기
프로퍼티의 이름 외에는 소유 클래스에 대한 정보가 없어도 일반 함수 QObject::property() 및 QObject::setProperty()를 사용하여 프로퍼티를 읽고 쓸 수 있습니다. 아래 코드 스니펫에서 QAbstractButton::setDown() 호출과 QObject::setProperty() 호출은 모두 프로퍼티를 "down"으로 설정합니다.
QPushButton *button = new QPushButton; QObject *object = button; button->setDown(true); object->setProperty("down", true);
WRITE
접근자를 통해 프로퍼티에 액세스하는 것이 더 빠르고 컴파일 시 더 나은 진단을 제공하므로 둘 중 더 낫지만, 이 방법으로 프로퍼티를 설정하려면 컴파일 시 클래스에 대해 알고 있어야 합니다. 이름으로 프로퍼티에 액세스하면 컴파일 시점에 모르는 클래스에 액세스할 수 있습니다. 런타임에 클래스의 QObject, QMetaObject, QMetaProperties 을 쿼리하여 클래스의 프로퍼티를 찾을 수 있습니다.
QObject *object = ... const QMetaObject *metaobject = object->metaObject(); int count = metaobject->propertyCount(); for (int i=0; i<count; ++i) { QMetaProperty metaproperty = metaobject->property(i); const char *name = metaproperty.name(); QVariant value = object->property(name); ... }
위의 코드 조각에서 QMetaObject::property()는 알 수 없는 클래스에 정의된 각 프로퍼티에 대한 metadata 을 가져오는 데 사용됩니다. 속성 이름은 메타데이터에서 가져와 QObject::property()로 전달하여 현재 object 에 있는 속성의 value 을 가져옵니다.
간단한 예제
QObject 에서 파생되고 Q_OBJECT 매크로를 사용하는 MyClass
클래스가 있다고 가정해 보겠습니다. 우선순위 값을 추적하기 위해 MyClass
에 프로퍼티를 선언하고 싶습니다. 프로퍼티의 이름은 priority
이며, 유형은 MyClass
에 정의된 Priority
이라는 열거 유형이 됩니다.
클래스의 비공개 섹션에서 Q_PROPERTY() 매크로를 사용하여 프로퍼티를 선언합니다. 필수 READ
함수의 이름은 priority
이며, WRITE
함수는 setPriority
입니다. 열거형 유형은 Q_ENUM() 매크로를 사용하여 메타객체 시스템에 등록해야 합니다. 열거 형을 등록하면 QObject::setProperty() 호출에서 열거자 이름을 사용할 수 있습니다. READ
및 WRITE
함수에 대한 자체 선언도 제공해야 합니다. MyClass
선언은 다음과 같이 보일 수 있습니다:
class MyClass : public QObject { Q_OBJECT Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged) public: MyClass(QObject *parent = nullptr); ~MyClass(); enum Priority { High, Low, VeryHigh, VeryLow }; Q_ENUM(Priority) void setPriority(Priority priority) { if (m_priority == priority) return; m_priority = priority; emit priorityChanged(priority); } Priority priority() const { return m_priority; } signals: void priorityChanged(Priority); private: Priority m_priority; };
READ
함수는 const이며 속성 유형을 반환합니다. WRITE
함수는 void를 반환하고 속성 유형의 매개변수가 정확히 하나만 있습니다. 메타 객체 컴파일러는 이러한 요구 사항을 적용합니다. WRITE
함수의 동일성 검사는 필수는 아니지만, 변경된 사항이 없는 경우 다른 곳에서 알림을 보내거나 재평가를 강제할 필요가 없으므로 좋은 관행입니다.
MyClass
의 인스턴스에 대한 포인터 또는 MyClass
의 인스턴스인 QObject 에 대한 포인터가 주어졌을 때 우선순위 속성을 설정하는 두 가지 방법이 있습니다:
MyClass *myinstance = new MyClass; QObject *object = myinstance; myinstance->setPriority(MyClass::VeryHigh); object->setProperty("priority", "VeryHigh");
이 예제에서는 속성 유형인 열거 유형을 MyClass
에서 선언하고 Q_ENUM() 매크로를 사용하여 메타객체 시스템에 등록합니다. 이렇게 하면 열거형 값을 setProperty() 호출에서와 같이 문자열로 사용할 수 있습니다. 열거 형이 다른 클래스에서 선언된 경우 정규화된 이름(예: OtherClass::Priority)이 필요하며, 다른 클래스에서도 QObject 을 상속하고 Q_ENUM() 매크로를 사용하여 열거 형을 등록해야 합니다.
비슷한 매크로인 Q_FLAG() 매크로도 사용할 수 있습니다. Q_ENUM ()와 마찬가지로 열거형 타입을 등록하지만, 이 매크로는 타입을 플래그 집합, 즉 함께 OR할 수 있는 값으로 표시합니다. I/O 클래스에 열거형 값 Read
및 Write
이 있을 수 있으며 QObject::setProperty()는 Read | Write
을 받을 수 있습니다. Q_FLAG()는 이 열거형 유형을 등록하는 데 사용해야 합니다.
동적 속성
QObject::setProperty()는 런타임에 클래스 인스턴스에 새 프로퍼티를 추가하는 데에도 사용할 수 있습니다. 이름과 값으로 호출할 때 주어진 이름의 프로퍼티가 QObject 에 존재하고 주어진 값이 프로퍼티의 유형과 호환되는 경우 값이 프로퍼티에 저장되고 true가 반환됩니다. 값이 프로퍼티의 유형과 호환되지 않으면 프로퍼티가 변경되지 않고 false가 반환됩니다. 그러나 지정된 이름의 속성이 QObject 에 존재하지 않는 경우(즉, Q_PROPERTY()로 선언되지 않은 경우) 지정된 이름과 값을 가진 새 속성이 QObject 에 자동으로 추가되지만 여전히 false가 반환됩니다. 즉, 특정 속성이 QObject 에 이미 존재한다는 것을 미리 알지 못하는 한 false를 반환하면 특정 속성이 실제로 설정되었는지 여부를 확인하는 데 사용할 수 없습니다.
동적 속성은 인스턴스 단위로 추가되므로 QMetaObject 이 아닌 QObject 에 추가됩니다. 프로퍼티 이름과 잘못된 QVariant 값을 QObject::setProperty()에 전달하여 인스턴스에서 프로퍼티를 제거할 수 있습니다. QVariant 의 기본 생성자는 잘못된 QVariant 을 생성합니다.
동적 프로퍼티는 컴파일 시 Q_PROPERTY()로 선언된 프로퍼티와 마찬가지로 QObject::property()로 쿼리할 수 있습니다.
프로퍼티 및 사용자 정의 유형
프로퍼티에 사용되는 사용자 정의 유형은 Q_DECLARE_METATYPE() 매크로를 사용하여 등록해야 해당 값을 QVariant 객체에 저장할 수 있습니다. 따라서 클래스 정의에서 Q_PROPERTY() 매크로를 사용하여 선언된 정적 프로퍼티와 런타임에 생성된 동적 프로퍼티 모두에 사용하기에 적합합니다.
클래스에 추가 정보 추가하기
프로퍼티 시스템에 연결된 추가 매크로 Q_CLASSINFO()는 클래스의 메타 객체에 추가 이름-값 쌍을 첨부하는 데 사용할 수 있습니다. 예를 들어 QML 객체 유형의 컨텍스트에서 프로퍼티를 기본 프로퍼티로 표시하는 데 사용됩니다:
Q_CLASSINFO("DefaultProperty", "content")
다른 메타 데이터와 마찬가지로 클래스 정보는 메타 객체를 통해 런타임에 액세스할 수 있습니다. 자세한 내용은 QMetaObject::classInfo()를 참조하세요.
바인딩 가능한 속성 사용
바인더블 프로퍼티를 구현하는 데는 세 가지 유형이 사용될 수 있습니다:
첫 번째는 바인더블 프로퍼티를 위한 일반 클래스입니다. 후자의 두 가지는 QObject.
예제를 포함한 자세한 내용은 위에서 언급한 클래스와 바인더블 프로퍼티 구현 및 사용에 대한 일반적인 팁을 참조하세요.
메타 객체 시스템, 시그널과 슬롯, Q_DECLARE_METATYPE(), QMetaType, QVariant, Qt 바인더블 프로퍼티, 그리고 C++에서 QML 유형 정의하기 등을참고하세요 .
© 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.