이 페이지에서

사용자 정의 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의 타입 시스템은 별도의 지원 없이는 이 클래스의 인스턴스를 저장, 검색 및 직렬화하는 방법을 파악할 수 없습니다. 예를 들어, Message 값을 QVariant 에 저장할 수 없습니다.

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<Message>(stored);
qDebug() << "Retrieved:" << retrieved;

Q_DECLARE_METATYPE() 매크로를 사용하면 이러한 값을 시그널의 인자로 사용할 수도 있지만, 이는 직접적인 시그널-슬롯 연결에서만 가능합니다. 사용자 정의 유형을 시그널 및 슬롯 메커니즘에서 일반적으로 사용할 수 있게 하려면 몇 가지 추가 작업이 필요합니다.

사용자 정의 객체의 생성 및 소멸

이전 절의 선언을 통해 해당 타입을 직접적인 신호-슬롯 연결에서 사용할 수는 있지만, 서로 다른 스레드에 있는 객체 간에 이루어지는 것과 같은 큐에 저장된 신호-슬롯 연결에서는 사용할 수 없습니다. 이는 메타 객체 시스템이 런타임에 사용자 정의 타입의 객체 생성 및 소멸을 처리하는 방법을 알지 못하기 때문입니다.

실행 시점에 객체를 생성할 수 있도록 하려면, ` qRegisterMetaType()` 템플릿 함수를 호출하여 메타 객체 시스템에 해당 타입을 등록해야 합니다. 또한, 해당 타입을 사용하는 첫 번째 연결을 설정하기 전에 이 함수를 호출하면, 큐 기반 신호-슬롯 통신에서도 해당 타입을 사용할 수 있게 됩니다.

'Queued Custom Type' 예제에서는 ` Block ` 클래스를 선언하며, 이 클래스는 ` main.cpp ` 파일에 등록되어 있습니다:

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().)

유형을 출력 가능하게 만들기

다음 코드와 같이 디버깅을 위해 사용자 정의 타입을 출력 가능하게 만드는 것은 종종 매우 유용합니다:

Message message(body, headers);
qDebug() << "Original:" << message;

이는 해당 타입에 대한 스트리밍 연산자를 생성함으로써 구현되며, 이 연산자는 대개 해당 타입의 헤더 파일에서 정의됩니다:

QDebug operator<<(QDebug dbg, const Message &message);

여기서 ` Message ` 타입에 대한 구현은 출력 형식을 가능한 한 가독성 있게 만들기 위해 상당한 노력을 기울였습니다:

QDebug operator<<(QDebug dbg, const Message &message)
{
    QDebugStateSaver saver(dbg);
    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() 함수의 설명서에는 해당 기능의 사용법과 제한 사항에 대한 더 자세한 정보가 포함되어 있습니다.

'Queued Custom Type' 예제는 이 문서에 설명된 기능을 사용하여 사용자 정의 유형을 구현하는 방법을 보여줍니다.

'디버깅 기법' 문서는 위에서 설명한 디버깅 메커니즘에 대한 개요를 제공합니다.

© 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.