속성 시스템
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]
[VIRTUAL]
[OVERRIDE]
[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 속성으로 내보내는 방법을 보여주는 예제입니다. 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액세서 함수는 선택 사항입니다. 이 함수는 속성 값을 설정하는 데 사용됩니다. 이 함수는 void를 반환해야 하며, 속성의 유형이거나 해당 유형에 대한 포인터 또는 참조인 인수를 정확히 하나만 받아야 합니다. 예를 들어, 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함수는 void를 반환해야 하며 매개변수를 받아서는 안 됩니다.NOTIFY신호는 선택 사항입니다. 정의된 경우, 속성의 값이 변경될 때마다 발생되는 해당 클래스의 기존 신호 하나를 지정해야 합니다.MEMBER변수에 대한NOTIFY신호는 매개변수를 0개 또는 1개 받아야 하며, 매개변수의 유형은 속성의 유형과 동일해야 합니다. 이 매개변수는 속성의 새로운 값을 받게 됩니다.NOTIFY신호는 예를 들어 QML에서 바인딩이 불필요하게 재평가되는 것을 방지하기 위해, 속성이 실제로 변경되었을 때만 발송되어야 합니다. 이 신호는 Qt API(QObject::setProperty, QMetaProperty 등)를 통해 속성이 변경될 때 자동으로 발송되지만, MEMBER가 직접 변경될 때는 발송되지 않습니다.REVISION숫자나REVISION()매크로는 선택 사항입니다. 포함될 경우, 이 매크로는 해당 속성과 그 알림 신호가 API의 특정 버전에서 사용되도록 정의합니다(일반적으로 QML에 노출하기 위함). 포함되지 않을 경우 기본값은 0입니다.DESIGNABLE속성은 해당 속성이 GUI 디자인 도구의 속성 편집기(예: Qt Widgets Designer)의 속성 편집기에 표시되어야 하는지 여부를 나타냅니다. 대부분의 속성은DESIGNABLE(기본값 true)입니다. 유효한 값은 true와 false입니다.SCRIPTABLE속성은 이 속성이 스크립팅 엔진에서 접근 가능해야 하는지 여부를 나타냅니다(기본값 true). 유효한 값은 true와 false입니다.STORED속성은 해당 속성이 독립적으로 존재하는 것으로 간주되어야 하는지, 아니면 다른 값에 의존하는 것으로 간주되어야 하는지를 나타냅니다. 또한 객체의 상태를 저장할 때 해당 속성 값을 반드시 저장해야 하는지도 나타냅니다. 대부분의 속성은 독립적(STORED, 기본값 true)이지만, 예를 들어 ` QWidget::minimumWidth()`의 경우 `STORED` 값이 `false`입니다. 이는 해당 값이 ` QSize`인 ` QWidget::minimumSize()` 속성의 width 구성 요소에서 가져오기 때문입니다.USER속성은 해당 속성이 클래스에 대해 사용자 표시용(user-facing) 속성으로 지정되었는지, 아니면 사용자 편집 가능(user-editable) 속성으로 지정되었는지를 나타냅니다. 일반적으로 클래스당USER속성은 하나만 존재합니다(기본값 false). 예를 들어, QAbstractButton::checked 는 (체크 가능한) 버튼에 대한 사용자 편집 가능 속성입니다. QItemDelegate 는 위젯의USER속성을 가져오고 설정한다는 점에 유의하십시오.BINDABLE bindableProperty속성은 해당 속성이 바인딩을 지원하며, 메타 객체 시스템(QMetaProperty)을 통해 이 속성에 대한 바인딩을 설정하고 검사할 수 있음을 나타냅니다.bindableProperty는 QBindable<T> 유형의 클래스 멤버 이름을 지정하며, 여기서 T는 속성 유형입니다. 이 속성은 Qt 6.0에서 도입되었습니다.CONSTANT속성이 존재하면 해당 속성 값이 상수임을 나타냅니다. 주어진 객체 인스턴스에 대해, 상수 속성의 READ 메서드는 호출될 때마다 동일한 값을 반환해야 합니다. 이 상수 값은 객체의 인스턴스에 따라 다를 수 있습니다. 상수 속성은 WRITE 메서드나 NOTIFY 신호를 가질 수 없습니다.FINAL,VIRTUAL,OVERRIDE수정자는 C++ 및 QML의 해당 수정자와 동일한 의미를 가지며, 메타 객체 수준에서 속성 재정의(overriding)를 명시적으로 지정할 수 있게 해줍니다.참고: 현재 moc은 이러한 수정자를 강제 적용하지 않습니다. 이들은 구문적으로 인식되며, 주로 QML Runtime 강제 적용 및 툴링 진단에 사용됩니다. 향후 버전에서는 모듈 간에 유효하지 않은 재정의에 대해 더 엄격한 컴파일 시점 유효성 검사 및 경고가 도입될 수 있습니다.
참고: 속성의 접근 동작을변경하려면 C++에서 제공하는 다형성을 사용하십시오.
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 = new QObject;
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 라는 열거형입니다.
클래스의 private 섹션에서 Q_PROPERTY() 매크로를 사용하여 속성을 선언합니다. 필수 함수인 READ 는 priority 로 명명되며, setPriority 라는 WRITE 함수도 포함합니다. 열거형 타입은 Q_ENUM() 매크로를 사용하여 메타 객체 시스템 ( Meta-Object System )에 등록해야 합니다. 열거형 타입을 등록하면 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를 반환하며, 속성 유형의 매개변수를 정확히 하나 가집니다. Meta-Object Compiler는 이러한 요구 사항을 강제 적용합니다. WRITE 함수 내의 동일성 확인은 필수 사항은 아니지만, 변경된 사항이 없는 경우 다른 곳에서 알림을 보내거나 재평가를 강제로 유발할 필요가 없으므로 권장되는 관행입니다.
MyClass 의 인스턴스에 대한 포인터나 MyClass 의 인스턴스인 QObject 에 대한 포인터가 주어지면, 해당 객체의 priority 속성을 설정하는 두 가지 방법이 있습니다:
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가 반환되었다고 해서 특정 속성이 실제로 설정되었는지 여부를 판단할 수는 없습니다.
동적 속성은 인스턴스 단위로 추가된다는 점에 유의하십시오. 즉, QObject 에 추가되며 QMetaObject 에는 추가되지 않습니다. QObject::setProperty()에 속성 이름과 유효하지 않은 QVariant 값을 전달하여 인스턴스에서 속성을 제거할 수 있습니다. QVariant 의 기본 생성자는 유효하지 않은 QVariant 를 생성합니다.
동적 속성은 QObject::property()을 사용하여 쿼리할 수 있으며, 이는 Q_PROPERTY()을 통해 컴파일 시점에 선언된 속성과 동일합니다.
속성과 사용자 정의 유형
속성에서 사용하는 사용자 정의 유형은 그 값을 QVariant 객체에 저장할 수 있도록 Q_DECLARE_METATYPE() 매크로를 사용하여 등록해야 합니다. 이를 통해 클래스 정의에서 Q_PROPERTY() 매크로를 사용하여 선언된 정적 속성과 런타임에 생성된 동적 속성 모두에 적합하게 사용할 수 있습니다.
클래스에 추가 정보 추가하기
속성 시스템과 연계된 또 다른 매크로인 Q_CLASSINFO()는 클래스의 메타 객체에 추가적인이름-값 쌍을 연결하는 데 사용할 수 있습니다. 예를 들어, QML Object Types 의 컨텍스트에서 특정 속성을 기본 속성으로 지정하는 데 이 매크로를 사용합니다:
Q_CLASSINFO("DefaultProperty", "content")다른 메타데이터와 마찬가지로, 클래스 정보는 실행 시 메타 객체를 통해 접근할 수 있습니다. 자세한 내용은 QMetaObject::classInfo()을 참조하십시오.
바인딩 가능한 속성 사용
바인딩 가능한 속성을 구현하는 데는 세 가지 유형을 사용할 수 있습니다:
첫 번째는 바인딩 가능한 속성을 위한 일반적인 클래스입니다. 나머지 두 가지는 QObject 내에서만 사용할 수 있습니다.
예제를 포함한 자세한 내용은 앞서 언급한 클래스와 바인딩 가능한 속성의 구현 및 사용에 관한 일반적인 팁을 참조하십시오.
또한 메타 객체 시스템, 시그널과 슬롯, Q_DECLARE_METATYPE(), QMetaType, QVariant, Qt 바인딩 가능한 속성, C++에서 QML 유형 정의 항목도참조하십시오 .
© 2026 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.