이 페이지에서

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 설치 디렉터리의 Examples/Qt-6.12.0/qml/tutorials/extending-qml/ 경로에서 소스 코드를 찾을 수 있습니다.

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

또는 소스 코드를 처음부터 직접 생성하여 튜토리얼을 따라갈 수도 있습니다. 각 장마다 Qt Quick 의 애플리케이션 템플릿을 사용하여 새 프로젝트를 생성하십시오:

그런 다음 생성된 스켈레톤 코드를 수정하고 확장하면서 따라가세요.

1장: 새 유형 만들기

extending-qml/chapter1-basics

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

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

먼저, ‘name’과 ‘color’라는 두 가지 속성을 가진 “PieChart”라는 새로운 QML 타입을 만들어 보겠습니다. 이 타입을 버전 1.0인 “Charts”라는 임포트 가능한 타입 네임스페이스에서 사용할 수 있도록 할 것입니다.

이 PieChart 타입을 QML에서 다음과 같이 사용할 수 있도록 할 것입니다:

import Charts

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

참고: Qt Creator 에서 PieChart 가 올바르게 강조 표시되도록 하려면 QML Language Server 및 해당 의미론적 강조 표시 기능을 활성화해야 할 수있습니다 ( Qt Creator 또는 Qt Extension for Visual Studio Code 에서 설정).

이를 위해서는 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 을 상속받는데, 이는 QQuickPaintedItem::paint()을 재정의하여 QPainter API를 통해 그리기 작업을 수행하기 위함입니다. 만약 이 클래스가 단순히 어떤 데이터 유형을 나타낼 뿐 실제로 표시되어야 하는 항목이 아니라면, QObject 을 상속받으면 됩니다. 또는 기존의 QObject 기반 클래스의 기능을 확장하고자 한다면, 대신 해당 클래스를 상속받을 수도 있습니다. 반대로, QPainter API를 사용하여 그리기 작업을 수행할 필요가 없는 시각적 항목을 생성하고자 한다면, QQuickItem 의 서브클래스를 만들면 됩니다.

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

qmake 설정

등록이 적용되려면 프로젝트 파일의 ` CONFIG `에 ` qmltypes ` 옵션을 추가하고, ` QML_IMPORT_NAME ` 및 ` QML_IMPORT_MAJOR_VERSION `를 지정해야 합니다.

CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1

또한, QML 모듈을 생성하려면 qmldir 파일을 수동으로 추가해야 합니다.

module Charts
typeinfo chapter1-basics.qmltypes
depends QtQuick
prefer :/qt/qml/Charts/
App 254.0 App.qml

CMake 설정

CMake를 사용할 때 등록이 적용되도록 하려면 qt_add_qml_module() 명령을 사용하십시오:

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

qt_add_qml_module() API는 QML 모듈에 대한 qmldir 파일을 자동으로 생성합니다.

클래스 구현

piechart.cpp 내의 클래스 구현은 m_name 및 m_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
    NO_UNSUPPORTED_PLATFORM_ERROR
    DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
install(SCRIPT ${deploy_script})

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

응용 프로그램은 파이 차트 유형에 정의된 속성을 사용하여 파이 차트를 생성합니다.

참고: “Expression ... depends on non-bindable properties: PieChart::name”이라는 경고가 표시될 수있습니다 . 이는 쓰기 가능한 name 속성에 바인딩을 추가했지만, 아직 이에 대한 notify 신호를 정의하지 않았기 때문입니다. 따라서 name 값이 변경되더라도 QML 엔진은 바인딩을 업데이트할 수 없습니다. 이 문제는 다음 장에서 다루겠습니다.

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"
    }
}

사용자는 애플리케이션 창의 아무 곳이나 클릭하여 차트를 지울 수 있습니다. 이렇게 하면 Clear Chart 메서드가 호출됩니다.

이를 위해 C++ 클래스에 ` clearChart() ` 메서드와 ` chartCleared() ` 신호를 추가합니다:

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

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

Q_INVOKABLE 를 사용하면 clearChart() 메서드를 Qt 메타 객체 시스템에서 사용할 수 있게 되며, 결과적으로 QML에서도 사용할 수 있게 됩니다.

참고: ` Q_INVOKABLE`을 사용하는 대신 메서드를 Qt 슬롯으로 선언할 수도있습니다 . public 및 protected 슬롯은 QML에서도 호출할 수 있기 때문입니다(private 슬롯은 호출할 수 없습니다).

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"
    }
}

원형 차트 B의 색상 속성은 원형 차트 A의 색상 속성과 연동되어 있습니다.

"color: chartA.color" 문은 chartB 의 color 값을 chartA 의 color 에 바인딩합니다. chartA 의 color 값이 변경될 때마다, chartB 의 color 값도 동일한 값으로 업데이트됩니다. 창을 클릭하면 MouseArea 의 onClicked 핸들러가 chartA 의 색상을 변경하여, 두 차트 모두 파란색으로 바뀝니다.

color 속성에 대한 속성 바인딩을 활성화하는 것은 간단합니다. 값이 변경될 때마다 "colorChanged" 신호가 발산되도록 하기 위해, 해당 속성의 Q_PROPERTY() 선언에 NOTIFY 기능을 추가합니다.

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 유형은 현재 문자열형 속성과 색상형 속성을 가지고 있습니다. 이 유형에는 다른 여러 유형의 속성이 있을 수 있습니다. 예를 들어, 각 차트의 식별자를 저장하기 위한 정수형 속성을 가질 수 있습니다:

// 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"라는 유형으로 대체해 보겠습니다. 색상을 할당하는 대신, ` color`를 포함하는 ` PieSlice ` 값을 할당합니다:

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 속성을 정의할 수 있습니다:

pragma ComponentBehavior: Bound
import Charts
import QtQuick

Item {
    width: 300; height: 200

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

        component Slice: PieSlice {
            parent: chart
            anchors.fill: parent
        }

        slices: [
            Slice {
                color: "red"
                fromAngle: 0
                angleSpan: 110
            },
            Slice {
                color: "black"
                fromAngle: 110
                angleSpan: 50
            },
            Slice {
                color: "blue"
                fromAngle: 160
                angleSpan: 100
            }
        ]
    }
}

slices 속성은 파이 슬라이스 항목들의 목록을 받아들입니다. pieslice 항목은 각 파이 슬라이스의 각도와 색상을 설정합니다.

이를 위해 ` PieChart `의 ` pieSlice ` 속성을 ` QQmlListProperty ` 유형으로 선언된 ` slices ` 속성으로 대체합니다. ` QQmlListProperty ` 클래스는 QML에 노출되는 유형에서 목록 속성을 생성할 수 있게 해줍니다. ` pieSlice() ` 함수를 슬라이스 목록을 반환하는 ` slices() ` 함수로 대체합니다. 또한 ` QList `를 사용하여 내부 슬라이스 목록을 ` m_slices`로 저장합니다:

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

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

slices 속성에는 WRITE 함수가 연관되어 있지 않지만, QQmlListProperty 의 작동 방식 덕분에 여전히 수정할 수 있습니다. PieChart 구현에서, PieChart::slices() 을 구현하여 QQmlListProperty 값을 반환하도록 합니다:

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

이렇게 하면 QML에서 목록과 상호작용하는 데 필요한 함수들이 합성됩니다. 결과적으로 생성된 QQmlListProperty 는 목록을 보여주는 뷰입니다. 또는, 목록에 대한 개별 액세스 함수를 수동으로 제공할 수도 있습니다. 이는 목록이 QList 가 아니거나, 목록에 대한 QML 액세스를 제한하거나 다른 방식으로 사용자 정의하려는 경우에 필요합니다. 그러나 대부분의 경우, ` QList ` 포인터를 인수로 받는 생성자를 사용하는 것이 가장 안전하고 쉬운 방법입니다.

PieSlice 클래스도 수정되어 fromAngle 및 angleSpan 속성을 포함하고, 이 값들에 따라 슬라이스를 그릴 수 있게 되었습니다. 이 튜토리얼의 앞부분을 읽으셨다면 이 수정은 간단하므로, 여기서는 코드를 생략합니다.

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

extending-qml/chapter6-plugins

현재 PieChart 및 PieSlice 유형은 App.qml 에서 사용되며, 이는 C++ 애플리케이션의 QQuickView 을 통해 표시됩니다. QML 확장 기능을 사용하는 또 다른 방법은 플러그인 라이브러리를 생성하여 QML 엔진에서 새로운 QML 임포트 모듈로 사용할 수 있도록 하는 것입니다. 이를 통해 PieChart 및 PieSlice 유형을 특정 애플리케이션에서만 사용하도록 제한하는 대신, 모든 QML 애플리케이션에서 임포트할 수 있는 유형 네임스페이스에 등록할 수 있습니다.

플러그인 생성 단계는 ‘QML용 C++ 플러그인 만들기’에 설명되어 있습니다. 우선, ChartsPlugin 라는 이름의 플러그인 클래스를 생성합니다. 이 클래스는 QQmlEngineExtensionPlugin 를 상속받으며, Q_PLUGIN_METADATA() 매크로를 사용하여 Qt 메타 객체 시스템에 플러그인을 등록합니다.

다음은 ` chartsplugin.h`에 정의된 ` ChartsPlugin `의 정의입니다.

#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;
    ...

사용자 정의 임포트 경로를 정의하는 것은 동일한 QML 임포트를 사용하는 애플리케이션이 여러 개 있을 때도 유용합니다.

.pro 파일에는 모듈 정의 qmldir 파일이 항상 플러그인 바이너리와 동일한 위치로 복사되도록 보장하는 추가적인 기능이 포함되어 있습니다.

qmldir 파일은 모듈 이름과 해당 모듈을 통해 제공되는 플러그인을 선언합니다:

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

이제 QML 엔진이 해당 모듈의 위치를 알 수만 있다면, 어떤 애플리케이션이든 이 QML 모듈을 임포트할 수 있습니다. 이 예제에는 ` App.qml` 파일을 불러오는 실행 파일이 포함되어 있으며, 이 파일은 ` import Charts 1.0 ` 문을 사용합니다. 또는 qml 도구를 사용하여 QML 파일을 불러올 때, ` qmldir ` 파일을 찾을 수 있도록 임포트 경로를 현재 디렉터리로 설정할 수도 있습니다:

qml -I . App.qml

"Charts" 모듈은 QML 엔진에 의해 로드되며, 이 모듈이 제공하는 타입들은 이를 임포트하는 모든 QML 문서에서 사용할 수 있습니다.

7장: 요약

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

  • QObject 을 상속하여 새로운 QML 타입을 정의하고, QML_ELEMENT 또는 QML_NAMED_ELEMENT()을 통해 등록합니다.
  • Q_INVOKABLE 또는 Qt 슬롯을 사용하여 호출 가능한 메서드를 추가하고, onSignal 구문을 통해 Qt 시그널에 연결합니다
  • NOTIFY 신호를 정의하여 속성 바인딩을 추가합니다
  • 내장 타입만으로는 충분하지 않은 경우 사용자 정의 속성 타입을 정의할 수 있습니다
  • 다음과 같이 목록 속성 유형을 정의합니다. QQmlListProperty
  • Qt 플러그인을 정의하고 qmldir 파일을 작성하여 플러그인 라이브러리를 생성합니다

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

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

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

PieChart {
    PieSliceRandomizer on slices {}
}

참고: QML 확장 및 기능에 대해 더 자세히알아보려면 ‘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.