사용자 정의 Qt 유형 만들기
개요
Qt로 사용자 인터페이스, 특히 특수 컨트롤과 기능이 있는 사용자 인터페이스를 만들 때 개발자는 때때로 Qt의 기존 값 유형 세트와 함께 또는 그 대신 사용할 수 있는 새로운 데이터 유형을 만들어야 할 때가 있습니다.
QSize, QColor, QString 와 같은 표준 유형은 모두 QVariant 객체에 저장하고 QObject 기반 클래스에서 속성 유형으로 사용하며 신호 슬롯 통신에서 방출할 수 있습니다.
이 문서에서는 사용자 정의 유형을 가져와서 표준 Qt 유형과 동일한 방식으로 저장할 수 있도록 Qt의 객체 모델에 통합하는 방법을 설명합니다. 그런 다음 사용자 정의 유형을 등록하여 신호 및 슬롯 연결에서 사용할 수 있도록 하는 방법을 보여줍니다.
사용자 정의 유형 생성하기
시작하기 전에 생성하려는 사용자 정의 유형이 QMetaType 에서 부과하는 모든 요구 사항을 충족하는지 확인해야 합니다. 즉, 다음을 제공해야 합니다:
- 공개 기본 생성자
- 공용 복사본 생성자, 그리고
- 공개 소멸자를 제공해야 합니다.
다음 Message
클래스 정의에는 이러한 멤버가 포함되어 있습니다:
class Message { public: Message() = default; ~Message() = default; Message(const Message &) = default; Message &operator=(const Message &) = default; Message(const QString &body, const QStringList &headers); QStringView body() const; QStringList headers() const; private: QString m_body; QStringList m_headers; };
이 클래스는 일반적인 사용을 위한 생성자와 비공개 데이터를 가져오는 데 사용되는 두 개의 공용 멤버 함수도 제공합니다.
QMetaType으로 유형 선언하기
Message
클래스는 적절한 구현만 있으면 사용할 수 있습니다. 그러나 Qt의 타입 시스템은 약간의 도움 없이는 이 클래스의 인스턴스를 저장, 검색 및 직렬화하는 방법을 이해할 수 없습니다. 예를 들어 QVariant 에 Message
값을 저장할 수 없습니다.
사용자 정의 형을 담당하는 Qt XML의 클래스는 QMetaType 입니다. 이 클래스에 유형을 알리기 위해 해당 유형이 정의된 헤더 파일의 클래스에서 Q_DECLARE_METATYPE() 매크로를 호출합니다:
Q_DECLARE_METATYPE(Message);
이제 Message
값을 QVariant 객체에 저장하고 나중에 검색할 수 있습니다:
QVariant stored; stored.setValue(message); ... Message retrieved = qvariant_cast<Message>(stored);qDebug() << "Retrieved:" << retrieved; retrieved = qvariant_cast<메시지>(저장됨);qDebug() << "Retrieved:" << retrieved;
Q_DECLARE_METATYPE() 매크로를 사용하면 이러한 값을 신호의 인수로 사용할 수도 있지만 신호-슬롯 직접 연결에서만 가능합니다. 사용자 정의 유형을 신호 및 슬롯 메커니즘에서 일반적으로 사용할 수 있게 하려면 몇 가지 추가 작업을 수행해야 합니다.
사용자 정의 객체 생성 및 삭제
이전 섹션의 선언을 통해 직접 신호-슬롯 연결에 사용할 수 있는 유형을 만들 수 있지만, 다른 스레드의 객체 간에 이루어지는 연결과 같이 대기 중인 신호-슬롯 연결에는 사용할 수 없습니다. 이는 메타 객체 시스템이 런타임에 사용자 정의 유형의 객체 생성 및 소멸을 처리하는 방법을 알지 못하기 때문입니다.
런타임에 객체를 생성하려면 qRegisterMetaType() 템플릿 함수를 호출하여 메타객체 시스템에 등록하세요. 이렇게 하면 해당 유형을 사용하는 첫 번째 연결을 하기 전에 호출하기만 하면 대기 중인 신호 슬롯 통신에 해당 유형을 사용할 수 있습니다.
대기열 사용자 정의 유형 예제에서는 main.cpp
파일에 등록된 Block
클래스를 선언합니다:
int main(int argc, char *argv[]) { QApplication app(argc, argv); ... qRegisterMetaType<Block>(); ... return app.exec(); }
이 유형은 나중에 window.cpp
파일의 신호 슬롯 연결에 사용됩니다:
Window::Window(QWidget *parent) : QWidget(parent), thread(new RenderThread(this)) { ... connect(thread, &RenderThread::sendBlock, this, &Window::addBlock); ... setWindowTitle(tr("Queued Custom Type")); }
유형이 등록되지 않은 채 대기열 연결에서 사용되는 경우 콘솔에 경고가 표시됩니다:
QObject::connect: Cannot queue arguments of type 'Block' (Make sure 'Block' is registered using qRegisterMetaType().)
유형을 인쇄 가능하게 만들기
다음 코드에서와 같이 디버깅 목적으로 사용자 정의 유형을 인쇄 가능하게 만드는 것은 종종 매우 유용합니다:
메시지 메시지(본문, 헤더);qDebug() << "Original:" << message;
이는 해당 유형의 헤더 파일에 정의된 유형에 대한 스트리밍 연산자를 생성하여 수행됩니다:
여기서의 Message
유형에 대한 구현은 인쇄 가능한 표현을 최대한 읽기 쉽게 만들기 위해 약간의 노력을 기울였습니다:
QDebug operator<<(QDebug dbg, const Message &message) { const QList<QStringView> pieces = message.body().split(u"\r\n", Qt::SkipEmptyParts); if (pieces.isEmpty()) dbg.nospace() << "Message()"; else if (pieces.size() == 1) dbg.nospace() << "Message(" << pieces.first() << ")"; else dbg.nospace() << "Message(" << pieces.first() << " ...)"; return dbg; }
물론 디버그 스트림으로 전송되는 출력은 원하는 만큼 단순하거나 복잡하게 만들 수 있습니다. 이 함수가 반환하는 값은 QDebug 객체 자체이지만, 가독성을 높이기 위해 공백 문자로 스트림을 채우는 QDebug 의 maybeSpace() 멤버 함수를 호출하여 얻을 수 있는 경우가 많다는 점에 유의하세요.
추가 읽기
Q_DECLARE_METATYPE() 매크로 및 qRegisterMetaType() 함수 문서에는 사용 방법과 제한 사항에 대한 자세한 정보가 나와 있습니다.
대기열 사용자 정의 유형 예제에서는 이 문서에 설명된 기능으로 사용자 정의 유형을 구현하는 방법을 보여줍니다.
디버깅 기법 문서에서는 위에서 설명한 디버깅 메커니즘에 대한 개요를 제공합니다.
© 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.