C++로 QML 확장 프로그램 작성

모듈은 Qt Qml 모듈은 C++ 확장을 통해 QML을 확장하기 위한 API 세트를 제공합니다. 확장을 작성하여 자신만의 QML 유형을 추가하거나, 기존 Qt 유형을 확장하거나, 일반 QML 코드에서 액세스할 수 없는 C/C++ 함수를 호출할 수 있습니다.

이 튜토리얼에서는 속성, 신호 및 바인딩을 포함한 핵심 QML 기능을 포함하는 C++를 사용하여 QML 확장을 작성하는 방법을 보여줍니다. 또한 플러그인을 통해 확장을 배포하는 방법도 보여줍니다.

이 튜토리얼에서 다루는 많은 주제는 개요 - QML과 C++ 통합 및 해당 문서 하위 주제에 자세히 설명되어 있습니다. 특히 하위 주제인 C++ 클래스의 속성을 QML에 노출하기C++에서 QML 유형 정의하기에 관심이 있을 수 있습니다.

튜토리얼 소스 열기

이 튜토리얼의 코드는 Qt 소스의 일부로 제공됩니다. Qt Online Installer 를 사용하여 Qt를 설치했다면, 예제/Qt-6.8.2/qml/tutorials/extending-qml/ 아래의 Qt 설치 디렉토리에서 소스를 찾을 수 있습니다.

처음부터 프로젝트 생성하기

또는 처음부터 소스를 생성하여 튜토리얼을 따라갈 수도 있습니다: 각 장에 대해 Qt Creator 에서 Qt Quick 애플리케이션 템플릿을 사용하여 Qt Creator 의 지침에 따라 새 프로젝트를 만듭니다: Qt Quick 프로젝트 만들기. 그런 다음 생성된 스켈레톤 코드를 조정하고 확장하여 따라하세요.

1장: 새 유형 만들기

extending-qml/chapter1-basics

QML을 확장할 때 흔히 하는 작업은 내장된 Qt Quick types. 예를 들어, 특정 데이터 모델을 구현하거나, 사용자 지정 페인팅 및 그리기 기능을 갖춘 유형을 제공하거나, 기본 제공 QML 기능으로는 액세스할 수 없는 네트워크 프로그래밍과 같은 시스템 기능에 액세스하기 위해 이 작업을 수행할 수 있습니다.

이 튜토리얼에서는 Qt Quick 모듈의 C++ 클래스를 사용하여 QML을 확장하는 방법을 보여드리겠습니다. 최종 결과는 바인딩 및 신호와 같은 QML 기능을 통해 서로 연결된 여러 사용자 정의 QML 유형으로 구현된 간단한 원형 차트 표시가 될 것이며 플러그인을 통해 QML 런타임에서 사용할 수 있게 됩니다.

우선 이름과 색이라는 두 가지 속성을 가진 "PieChart"라는 새로운 QML 유형을 만들어 보겠습니다. "Charts"라는 가져오기 가능한 유형 네임스페이스에서 1.0 버전으로 사용할 수 있도록 하겠습니다.

PieChart 타입을 QML에서 다음과 같이 사용할 수 있기를 원합니다:

import Charts

PieChart {
    width: 100; height: 100
    name: "A simple pie chart"
    color: "red"
}

이를 위해서는 이 PieChart 유형과 그 속성을 캡슐화하는 C++ 클래스가 필요합니다. QML은 Qt의 메타 객체 시스템을 광범위하게 사용하므로 이 새로운 클래스는 반드시 필요합니다:

  • 다음에서 상속합니다. QObject
  • Q_PROPERTY 매크로를 사용하여 프로퍼티를 선언합니다.

클래스 선언

다음은 piechart.h 에 정의된 PieChart 클래스입니다:

#include <QtQuick/QQuickPaintedItem>
#include <QColor>

class PieChart : public QQuickPaintedItem
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName FINAL)
    Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
    QML_ELEMENT

public:
    PieChart(QQuickItem *parent = nullptr);

    QString name() const;
    void setName(const QString &name);

    QColor color() const;
    void setColor(const QColor &color);

    void paint(QPainter *painter) override;

private:
    QString m_name;
    QColor m_color;
};

이 클래스는 QQuickPaintedItem::paint()를 재정의하여 QPainter API로 그리기 작업을 수행하기 때문에 QQuickPaintedItem 에서 상속합니다. 클래스가 일부 데이터 유형만 나타내며 실제로 표시해야 하는 항목이 아니라면 QObject 에서 상속할 수 있습니다. 또는 기존 QObject 기반 클래스의 기능을 확장하려는 경우 해당 클래스를 대신 상속할 수 있습니다. 또는 QPainter API로 그리기 작업을 수행할 필요가 없는 시각적 항목을 만들려면 QQuickItem 클래스를 서브클래싱하면 됩니다.

PieChart 클래스는 Q_PROPERTY 매크로를 사용하여 namecolor 두 속성을 정의하고 QQuickPaintedItem::paint()를 재정의합니다. PieChart 클래스는 QML_ELEMENT 매크로를 사용하여 등록하여 QML에서 사용할 수 있도록 합니다. 클래스를 등록하지 않으면 App.qml 에서 PieChart 을 생성할 수 없습니다.

qmake 설정

등록을 적용하려면 프로젝트 파일의 CONFIGqmltypes 옵션을 추가하고 QML_IMPORT_NAMEQML_IMPORT_MAJOR_VERSION 을 지정해야 합니다:

CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1

CMake 설정

마찬가지로 CMake를 사용할 때 등록을 적용하려면 qt_add_qml_module 명령을 사용합니다:

qt_add_qml_module(chapter1-basics
    URI Charts
    QML_FILES App.qml
    DEPENDENCIES QtQuick
)

클래스 구현

piechart.cpp 의 클래스 구현은 m_namem_color 값을 적절히 설정하여 반환하고 paint() 을 구현하여 간단한 파이 차트를 그리기만 하면 됩니다:

PieChart::PieChart(QQuickItem *parent)
    : QQuickPaintedItem(parent)
{
}
...
void PieChart::paint(QPainter *painter)
{
    QPen pen(m_color, 2);
    painter->setPen(pen);
    painter->setRenderHints(QPainter::Antialiasing, true);
    painter->drawPie(boundingRect().adjusted(1, 1, -1, -1), 90 * 16, 290 * 16);
}

QML 사용

이제 PieChart 유형을 정의했으므로 QML에서 이를 사용하겠습니다. App.qml 파일은 PieChart 항목을 생성하고 표준 QML Text 항목을 사용하여 원형 차트의 세부 정보를 표시합니다:

import Charts
import QtQuick

Item {
    width: 300; height: 200

    PieChart {
        id: aPieChart
        anchors.centerIn: parent
        width: 100; height: 100
        name: "A simple pie chart"
        color: "red"
    }

    Text {
        anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
        text: aPieChart.name
    }
}

QML에서 색상이 문자열로 지정되어 있지만 PieChart color 속성에 대해 자동으로 QColor 객체로 변환된다는 점에 유의하세요. 다른 다양한 값 유형에 대해서도 자동 변환이 제공됩니다. 예를 들어, "640x480"과 같은 문자열은 QSize 값으로 자동 변환될 수 있습니다.

또한 QQuickView 을 사용하여 App.qml 을 실행하고 표시하는 C++ 애플리케이션을 만들어 보겠습니다.

다음은 애플리케이션 main.cpp 입니다:

#include "piechart.h"
#include <QtQuick/QQuickView>
#include <QGuiApplication>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQuickView view;
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    view.loadFromModule("Charts", "App");
    view.show();
    return QGuiApplication::exec();
}

프로젝트 빌드

프로젝트를 빌드하기 위해 파일을 포함하고, 라이브러리에 대해 링크하고, QML에 노출된 모든 유형에 대해 버전 1.0의 "Charts"라는 유형 네임스페이스를 정의합니다.

qmake 사용:

QT += qml quick

CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1

HEADERS += piechart.h
SOURCES += piechart.cpp \
           main.cpp

RESOURCES += chapter1-basics.qrc

DESTPATH = $$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending-qml/chapter1-basics
target.path = $$DESTPATH
INSTALLS += target

CMake 사용:

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

cmake_minimum_required(VERSION 3.16)
project(chapter1-basics LANGUAGES CXX)

find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)

qt_standard_project_setup(REQUIRES 6.8)

qt_add_executable(chapter1-basics
    main.cpp
    piechart.cpp piechart.h
)

set_target_properties(chapter1-basics PROPERTIES
    WIN32_EXECUTABLE TRUE
    MACOSX_BUNDLE TRUE
)

target_link_libraries(chapter1-basics PUBLIC
    Qt6::Core
    Qt6::Gui
    Qt6::Qml
    Qt6::Quick
)
qt_add_qml_module(chapter1-basics
    URI Charts
    QML_FILES App.qml
    DEPENDENCIES QtQuick
)
install(TARGETS chapter1-basics
    BUNDLE  DESTINATION .
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

qt_generate_deploy_qml_app_script(
    TARGET chapter1-basics
    OUTPUT_SCRIPT deploy_script
    MACOS_BUNDLE_POST_BUILD
    NO_UNSUPPORTED_PLATFORM_ERROR
    DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
install(SCRIPT ${deploy_script})

이제 애플리케이션을 빌드하고 실행할 수 있습니다:

참고: 표현식 ...은 NOTIFY할 수 없는 속성에 의존한다는 경고가 표시될 수 있습니다: PieChart::name. 이는 쓰기 가능한 name 속성에 바인딩을 추가했지만 아직 해당 속성에 대한 알림 신호를 정의하지 않았기 때문에 발생합니다. 따라서 QML 엔진은 name 값이 변경되면 바인딩을 업데이트할 수 없습니다. 이 문제는 다음 장에서 다룹니다.

2장: C++ 메서드 및 시그널에 연결하기

extending-qml/chapter2-methods

PieChart 에 차트를 지운 다음 "chartCleared" 신호를 내보내는 "clearChart()" 메서드가 있다고 가정해 보겠습니다. 그러면 App.qml 에서 clearChart() 을 호출하고 chartCleared() 신호를 수신할 수 있습니다:

import Charts
import QtQuick

Item {
    width: 300; height: 200

    PieChart {
        id: aPieChart
        anchors.centerIn: parent
        width: 100; height: 100
        color: "red"

        onChartCleared: console.log("The chart has been cleared")
    }

    MouseArea {
        anchors.fill: parent
        onClicked: aPieChart.clearChart()
    }

    Text {
        anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
        text: "Click anywhere to clear the chart"
    }
}

이를 위해 C++ 클래스에 clearChart() 메서드와 chartCleared() 시그널을 추가합니다:

class PieChart : public QQuickPaintedItem
{
    ...
public:
    ...
    Q_INVOKABLE void clearChart();

signals:
    void chartCleared();
    ...
};

Q_INVOKABLE 을 사용하면 clearChart() 메서드를 Qt 메타 객체 시스템에서 사용할 수 있고, 차례로 QML에서도 사용할 수 있습니다.

참고: 공개 슬롯과 보호 슬롯도 QML에서 호출할 수 있으므로 Q_INVOKABLE 을 사용하는 대신 메서드를 Qt 슬롯으로 선언할 수도 있습니다(비공개 슬롯은 호출할 수 없음).

clearChart() 메서드는 색상을 Qt::transparent 으로 변경하고 차트를 다시 칠한 다음 chartCleared() 신호를 내보냅니다:

void PieChart::clearChart()
{
    setColor(QColor(Qt::transparent));
    update();

    emit chartCleared();
}

이제 애플리케이션을 실행하고 창을 클릭하면 원형 차트가 사라지고 애플리케이션이 출력됩니다:

qml: The chart has been cleared

3장: 속성 바인딩 추가하기

extending-qml/chapter3-bindings

속성 바인딩은 서로 다른 유형의 값을 자동으로 동기화할 수 있는 QML의 강력한 기능입니다. 프로퍼티 값이 변경되면 신호를 사용하여 다른 유형의 값을 알리고 업데이트합니다.

color 프로퍼티에 대해 프로퍼티 바인딩을 활성화해 보겠습니다. 즉, 다음과 같은 코드가 있습니다:

import Charts
import QtQuick

Item {
    width: 300; height: 200

    Row {
        anchors.centerIn: parent
        spacing: 20

        PieChart {
            id: chartA
            width: 100; height: 100
            color: "red"
        }

        PieChart {
            id: chartB
            width: 100; height: 100
            color: chartA.color
        }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: { chartA.color = "blue" }
    }

    Text {
        anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
        text: "Click anywhere to change the chart color"
    }
}

"color: chartA.color" 문은 chartBcolor 값을 colorchartA 에 바인딩합니다. chartAcolor 값이 변경될 때마다 chartBcolor 값도 같은 값으로 업데이트됩니다. 창을 클릭하면 MouseAreaonClicked 핸들러가 chartA 의 색을 변경하여 두 차트를 모두 파란색으로 변경합니다.

color 속성에 대한 속성 바인딩은 쉽게 활성화할 수 있습니다. Q_PROPERTY () 선언에 NOTIFY 기능을 추가하여 값이 변경될 때마다 "colorChanged" 신호가 발생함을 나타냅니다.

class PieChart : public QQuickPaintedItem
{
    ...
    Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL)
public:
    ...
signals:
    void colorChanged();
    ...
};

그런 다음 setColor() 에서 이 신호를 내보냅니다:

void PieChart::setColor(const QColor &color)
{
    if (color != m_color) {
        m_color = color;
        update();   // repaint with the new color
        emit colorChanged();
    }
}

setColor() 에서 colorChanged() 을 전송하기 전에 색상 값이 실제로 변경되었는지 확인하는 것이 중요합니다. 이렇게 하면 신호가 불필요하게 방출되지 않고 다른 유형이 값 변경에 응답할 때 루프를 방지할 수 있습니다.

바인딩의 사용은 QML에 필수적입니다. 프로퍼티를 바인딩에 사용할 수 있도록 구현할 수 있는 경우 항상 프로퍼티에 대한 NOTIFY 신호를 추가해야 합니다. 바인딩할 수 없는 프로퍼티는 자동으로 업데이트할 수 없으며 QML에서 유연하게 사용할 수 없습니다. 또한 바인딩은 QML 사용에서 매우 자주 호출되고 의존하기 때문에 바인딩이 구현되지 않은 경우 사용자 지정 QML 유형 사용자에게 예기치 않은 동작이 표시될 수 있습니다.

4장: 사용자 지정 속성 유형 사용

extending-qml/chapter4-customPropertyTypes

PieChart 유형에는 현재 문자열 유형 프로퍼티와 색상 유형 프로퍼티가 있습니다. 다른 많은 유형의 프로퍼티를 가질 수 있습니다. 예를 들어, 각 차트에 대한 식별자를 저장하는 int 유형 속성을 가질 수 있습니다:

// C++
class PieChart : public QQuickPaintedItem
{
    Q_PROPERTY(int chartId READ chartId WRITE setChartId NOTIFY chartIdChanged)
    ...

public:
    void setChartId(int chartId);
    int chartId() const;
    ...

signals:
    void chartIdChanged();
};

// QML
PieChart {
    ...
    chartId: 100
}

int 외에도 다양한 프로퍼티 유형을 사용할 수 있습니다. QColor , QSize, QRect 와 같은 많은 Qt 데이터 유형은 QML에서 자동으로 지원됩니다. (전체 목록은 QML과 C++ 간의 데이터 유형 변환 문서를 참조하세요.)

QML에서 기본적으로 지원되지 않는 타입의 프로퍼티를 생성하려면 해당 타입을 QML 엔진에 등록해야 합니다.

예를 들어 property 대신 color 프로퍼티가 있는 "PieSlice"라는 유형을 사용한다고 가정해 보겠습니다. 색상을 할당하는 대신 PieSlice 값을 할당하고 그 자체에 color 을 포함합니다:

import Charts
import QtQuick

Item {
    width: 300; height: 200

    PieChart {
        id: chart
        anchors.centerIn: parent
        width: 100; height: 100

        pieSlice: PieSlice {
            anchors.fill: parent
            color: "red"
        }
    }

    Component.onCompleted: console.log("The pie is colored " + chart.pieSlice.color)
}

PieChart 와 마찬가지로 이 새로운 PieSlice 유형은 QQuickPaintedItem 에서 상속되며 Q_PROPERTY()로 속성을 선언합니다:

class PieSlice : public QQuickPaintedItem
{
    Q_OBJECT
    Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
    QML_ELEMENT

public:
    PieSlice(QQuickItem *parent = nullptr);

    QColor color() const;
    void setColor(const QColor &color);

    void paint(QPainter *painter) override;

private:
    QColor m_color;
};

PieChart 에서 사용하려면 color 속성 선언과 관련 메서드 서명을 수정합니다:

class PieChart : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(PieSlice* pieSlice READ pieSlice WRITE setPieSlice FINAL)
    ...
public:
    ...
    PieSlice *pieSlice() const;
    void setPieSlice(PieSlice *pieSlice);
    ...
};

setPieSlice() 을 구현할 때 한 가지 주의해야 할 점이 있습니다. PieSlice 는 시각적 항목이므로 QQuickItem::setParentItem()를 사용하여 PieChart 의 하위 항목으로 설정해야 PieChart 이 내용을 그릴 때 이 하위 항목을 그리는 것을 알 수 있습니다:

void PieChart::setPieSlice(PieSlice *pieSlice)
{
    m_pieSlice = pieSlice;
    pieSlice->setParentItem(this);
}

PieChart 유형과 마찬가지로 PieSlice 유형은 QML_ELEMENT 를 사용하여 QML에 익스포스팅해야 합니다.

class PieSlice : public QQuickPaintedItem
{
    Q_OBJECT
    Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
    QML_ELEMENT

public:
    PieSlice(QQuickItem *parent = nullptr);

    QColor color() const;
    void setColor(const QColor &color);

    void paint(QPainter *painter) override;

private:
    QColor m_color;
};
    ...

PieChart 와 마찬가지로 빌드 파일에 "Charts" 타입 네임스페이스 버전 1.0을 추가합니다:

qmake 사용:

QT += qml quick

CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1

HEADERS += piechart.h \
           pieslice.h
SOURCES += piechart.cpp \
           pieslice.cpp \
           main.cpp

RESOURCES += chapter4-customPropertyTypes.qrc

DESTPATH = $$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending-qml/chapter4-customPropertyTypes
target.path = $$DESTPATH
INSTALLS += target

CMake 사용하기:

    ...
qt_add_executable(chapter4-customPropertyTypes
    main.cpp
    piechart.cpp piechart.h
    pieslice.cpp pieslice.h
)
qt_add_qml_module(chapter4-customPropertyTypes
    URI Charts
    QML_FILES App.qml
    DEPENDENCIES QtQuick
)
    ...

5장: 목록 속성 유형 사용하기

extending-qml/chapter5-listproperties

현재 PieChart 에는 PieSlice 만 하나만 있을 수 있습니다. 이상적으로는 차트에 색상과 크기가 다른 여러 개의 슬라이스가 있는 것이 좋습니다. 이를 위해 PieSlice 항목의 목록을 허용하는 slices 프로퍼티를 만들 수 있습니다:

import Charts
import QtQuick

Item {
    width: 300; height: 200

    PieChart {
        anchors.centerIn: parent
        width: 100; height: 100

        slices: [
            PieSlice {
                anchors.fill: parent
                color: "red"
                fromAngle: 0; angleSpan: 110
            },
            PieSlice {
                anchors.fill: parent
                color: "black"
                fromAngle: 110; angleSpan: 50
            },
            PieSlice {
                anchors.fill: parent
                color: "blue"
                fromAngle: 160; angleSpan: 100
            }
        ]
    }
}

이를 위해 PieChartpieSlice 속성을 slices 속성으로 바꾸고 QQmlListProperty 유형으로 선언합니다. QQmlListProperty 클래스를 사용하면 QML 확장에 목록 속성을 만들 수 있습니다. pieSlice() 함수를 슬라이스 목록을 반환하는 slices() 함수로 바꾸고 내부 append_slice() 함수를 추가합니다(아래 설명 참조). 또한 QList 을 사용하여 내부 슬라이스 목록을 m_slices 으로 저장합니다:

class PieChart : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(QQmlListProperty<PieSlice> slices READ slices FINAL)
    ...
public:
    ...
    QQmlListProperty<PieSlice> slices();

private:
    static void append_slice(QQmlListProperty<PieSlice> *list, PieSlice *slice);

    QString m_name;
    QList<PieSlice *> m_slices;
};

slices 속성에는 연결된 WRITE 함수가 없지만 QQmlListProperty 작동 방식 때문에 여전히 수정할 수 있습니다. PieChart 구현에서는 PieChart::slices() 을 구현하여 QQmlListProperty 값을 반환하고 QML에서 목록에 항목을 추가하라는 요청이 있을 때마다 내부 PieChart::append_slice() 함수가 호출되도록 지정합니다:

QQmlListProperty<PieSlice> PieChart::slices()
{
    return QQmlListProperty<PieSlice>(this, nullptr, &PieChart::append_slice, nullptr,
                                      nullptr, nullptr, nullptr, nullptr);
}

void PieChart::append_slice(QQmlListProperty<PieSlice> *list, PieSlice *slice)
{
    PieChart *chart = qobject_cast<PieChart *>(list->object);
    if (chart) {
        slice->setParentItem(chart);
        chart->m_slices.append(slice);
    }
}

append_slice() 함수는 이전과 마찬가지로 부모 항목을 설정하고 새 항목을 m_slices 목록에 추가하기만 하면 됩니다. 보시다시피 QQmlListProperty 함수는 목록 속성과 추가할 항목이라는 두 가지 인수를 사용하여 호출됩니다.

PieSlice 클래스도 fromAngleangleSpan 속성을 포함하고 이 값에 따라 슬라이스를 그리도록 수정되었습니다. 이 튜토리얼의 이전 페이지를 읽었다면 간단하게 수정할 수 있으므로 여기서는 코드를 표시하지 않습니다.

6장: 확장 플러그인 작성하기

extending-qml/chapter6-plugins

현재 PieChartPieSlice 유형은 C++ 애플리케이션에서 QQuickView 을 사용하여 표시되는 App.qml 에서 사용됩니다. QML 확장을 사용하는 또 다른 방법은 플러그인 라이브러리를 만들어 QML 엔진에서 새로운 QML 가져오기 모듈로 사용할 수 있도록 하는 것입니다. 이렇게 하면 PieChartPieSlice 유형을 하나의 애플리케이션에서만 사용하도록 제한하는 대신 모든 QML 애플리케이션에서 가져올 수 있는 유형 네임스페이스에 등록할 수 있습니다.

플러그인을 만드는 단계는 QML용 C++ 플러그인 만들기에 설명되어 있습니다. 우선 ChartsPlugin 이라는 플러그인 클래스를 만듭니다. 이 클래스는 QQmlEngineExtensionPlugin 을 서브클래스하고 Q_PLUGIN_METADATA() 매크로를 사용하여 플러그인을 Qt 메타 객체 시스템에 등록합니다.

다음은 chartsplugin.hChartsPlugin 정의입니다:

#include <QQmlEngineExtensionPlugin>

class ChartsPlugin : public QQmlEngineExtensionPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)
};

그런 다음 프로젝트를 플러그인 라이브러리로 정의하도록 빌드 파일을 구성합니다.

qmake 사용하기:

TEMPLATE = lib
CONFIG += plugin qmltypes
QT += qml quick

QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1

TARGET = $$qtLibraryTarget(chartsplugin)

HEADERS += piechart.h \
           pieslice.h \
           chartsplugin.h

SOURCES += piechart.cpp \
           pieslice.cpp

DESTPATH=$$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending-qml/chapter6-plugins/$$QML_IMPORT_NAME

target.path=$$DESTPATH
qmldir.files=$$PWD/qmldir
qmldir.path=$$DESTPATH
INSTALLS += target qmldir

CONFIG += install_ok  # Do not cargo-cult this!

OTHER_FILES += qmldir

# Copy the qmldir file to the same folder as the plugin binary
cpqmldir.files = qmldir
cpqmldir.path = .
COPIES += cpqmldir

CMake 사용:

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

qt6_policy(SET QTP0001 NEW)
qt6_add_qml_module(chartsplugin
    URI "Charts"
    PLUGIN_TARGET chartsplugin
    DEPENDENCIES QtQuick
)

target_sources(chartsplugin PRIVATE
    piechart.cpp piechart.h
    pieslice.cpp pieslice.h
)

target_link_libraries(chartsplugin PRIVATE
    Qt6::Core
    Qt6::Gui
    Qt6::Qml
    Qt6::Quick
)

install(TARGETS chartsplugin
    RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/Charts"
    LIBRARY DESTINATION "${CMAKE_INSTALL_BINDIR}/Charts"
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qmldir
    DESTINATION "${CMAKE_INSTALL_BINDIR}/Charts"
)

Windows 또는 Linux에서 이 예제를 빌드할 때 Charts 디렉터리는 새 가져오기 모듈을 사용하는 애플리케이션과 같은 레벨에 위치합니다. 이렇게 하면 QML 가져오기의 기본 검색 경로에 애플리케이션 실행 파일의 디렉터리가 포함되므로 QML 엔진이 모듈을 찾을 수 있습니다. macOS의 경우 플러그인 바이너리는 애플리케이션 번들에서 Contents/PlugIns 에 복사됩니다. qmake를 사용하면 이 경로는 chapter6-plugins/app.pro 로 설정됩니다:

macos:!qtConfig(static) {
    charts.files = $$OUT_PWD/Charts
    charts.path = Contents/PlugIns
    QMAKE_BUNDLE_DATA += charts
}

이를 고려하기 위해 main.cpp 에도 이 위치를 QML 가져오기 경로로 추가해야 합니다:

    QQuickView view;
#ifdef Q_OS_MACOS
    view.engine()->addImportPath(app.applicationDirPath() + "/../PlugIns");
#endif
    ...

사용자 지정 가져오기 경로를 정의하는 것은 동일한 QML 가져오기를 사용하는 애플리케이션이 여러 개 있는 경우에도 유용합니다.

.pro 파일에는 모듈 정의 qmldir 파일이 항상 플러그인 바이너리와 같은 위치에 복사되도록 하는 추가 마법도 포함되어 있습니다.

qmldir 파일은 모듈 이름과 모듈에서 사용할 수 있는 플러그인을 선언합니다:

module Charts
optional plugin chartsplugin
typeinfo plugins.qmltypes
depends QtQuick
prefer :/qt/qml/Charts/

이제 QML 엔진이 모듈을 찾을 수 있는 위치만 알고 있다면 모든 애플리케이션으로 가져올 수 있는 QML 모듈이 생겼습니다. 이 예제에는 import Charts 1.0 문을 사용하는 App.qml 을 로드하는 실행 파일이 포함되어 있습니다. 또는 qmldir 파일을 찾도록 가져오기 경로를 현재 디렉터리로 설정하여 qml 도구를 사용하여 QML 파일을 로드할 수도 있습니다:

qml -I . App.qml

"Charts" 모듈은 QML 엔진에 의해 로드되며, 해당 모듈에서 제공하는 유형은 이를 가져오는 모든 QML 문서에서 사용할 수 있습니다.

7장: 요약

이 튜토리얼에서는 QML 확장을 만드는 기본 단계를 보여드렸습니다:

  • QObject 을 서브클래싱하고 QML_ELEMENT 또는 QML_NAMED_ELEMENT()에 등록하여 새 QML 유형을 정의합니다.
  • Q_INVOKABLE 또는 Qt 슬롯을 사용하여 호출 가능한 메서드를 추가하고 onSignal 구문을 사용하여 Qt 신호에 연결합니다.
  • NOTIFY 신호를 정의하여 프로퍼티 바인딩 추가하기
  • 기본 제공 유형이 충분하지 않은 경우 사용자 정의 속성 유형 정의하기
  • 다음을 사용하여 목록 속성 유형 정의 QQmlListProperty
  • Qt 플러그인을 정의하고 qmldir 파일을 작성하여 플러그인 라이브러리 생성하기

QML 및 C++ 통합 개요 문서에는 QML 확장에 추가할 수 있는 다른 유용한 기능이 나와 있습니다. 예를 들어 기본 속성을 사용하여 slices 속성을 사용하지 않고 슬라이스를 추가할 수 있습니다:

PieChart {
    PieSlice { ... }
    PieSlice { ... }
    PieSlice { ... }
}

또는 속성 값 소스를 사용하여 수시로 슬라이스를 임의로 추가 및 제거할 수 있습니다:

PieChart {
    PieSliceRandomizer on slices {}
}

참고: QML 확장 및 기능에 대해 계속 알아보려면 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.