씬 그래프 - 페인팅된 항목
QPainter 를 기반으로 한 사용자 정의 씬그래프 항목을 구현하는 방법을 보여줍니다.
'Painted Item' 예제는 QML 씬 그래프 프레임워크를 사용하여 QPainter 을 기반으로 사용자 정의 씬 그래프 항목을 구현하는 방법을 보여줍니다.

QQuickPaintedItem 클래스는 QPainter 인터페이스를 사용하여 사용자 정의 QML 씬 그래프 항목을 구현하기 위해 QQuickItem 에서 파생된 클래스입니다.
이 예제는 항목 클래스와 해당 항목을 사용하는 QML 파일로 구성되어 있습니다. ` TextBalloon ` 클래스는 ` QQuickPaintedItem `를 확장하여 개별 텍스트 풍선을 나타내며, ` textballoons.qml ` 파일은 `TextBalloon` QML 유형이 포함된 모듈을 불러와 텍스트 풍선을 표시하는 데 사용됩니다.
먼저 TextBalloon 클래스에 대해 살펴본 후, textballoons.qml 파일을 계속 살펴보겠습니다. QML 모듈용 플러그인을 구현하는 방법에 대한 예제는 ‘확장 플러그인 작성(Writing an Extension Plugin)’을 참조하십시오.
TextBalloon 클래스 선언
TextBalloon 클래스는 QQuickPaintedItem 을 상속받습니다. QQuickPaintedItem 은 QML Scene Graph 프레임워크에서 QPainter 을 기반으로 하는 모든 항목의 기본 클래스입니다.
class TextBalloon : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(bool rightAligned READ isRightAligned WRITE setRightAligned NOTIFY rightAlignedChanged)
QML_ELEMENT
public:
TextBalloon(QQuickItem *parent = nullptr);
void paint(QPainter *painter) override;
bool isRightAligned() const;
void setRightAligned(bool rightAligned);
private:
bool rightAligned;
signals:
void rightAlignedChanged();
};QQuickPaintedItem 을 구현하려면, 해당 타입의 그리기 작업을 구현하는 QQuickPaintedItem의 순수 가상 함수 paint()를 구현해야 합니다.
TextBalloon 클래스 정의
TextBalloon 항목의 경우 rightAligned 속성을 반드시 초기화해야 합니다.
TextBalloon::TextBalloon(QQuickItem *parent)
: QQuickPaintedItem(parent)
, rightAligned(false)
{
}그런 다음, 씬 그래프 프레임워크가 항목의 내용을 그리기 위해 자동으로 호출하는 ` paint() ` 함수를 구현합니다. 이 함수는 로컬 좌표계에서 항목을 그립니다.
void TextBalloon::paint(QPainter *painter)
{
QBrush brush(QColor("#007430"));
painter->setBrush(brush);
painter->setPen(Qt::NoPen);
painter->setRenderHint(QPainter::Antialiasing);
QSizeF itemSize = size();
painter->drawRoundedRect(0, 0, itemSize.width(), itemSize.height() - 10, 10, 10);
if (rightAligned)
{
const QPointF points[3] = {
QPointF(itemSize.width() - 10.0, itemSize.height() - 10.0),
QPointF(itemSize.width() - 20.0, itemSize.height()),
QPointF(itemSize.width() - 30.0, itemSize.height() - 10.0),
};
painter->drawConvexPolygon(points, 3);
}
else
{
const QPointF points[3] = {
QPointF(10.0, itemSize.height() - 10.0),
QPointF(20.0, itemSize.height()),
QPointF(30.0, itemSize.height() - 10.0),
};
painter->drawConvexPolygon(points, 3);
}
}먼저 항목의 모양을 정의하기 위해 항목의 펜과 브러시를 설정합니다. 그 후 그리기를 시작합니다. 항목의 크기에 따라 contentsBoundingRect() 함수가 호출되어 그리기가 수행된다는 점에 유의하십시오. contentsBoundingRect() 함수가 반환하는 사각형은 QML 파일에 정의된 항목의 크기입니다.
textballoons.qml 파일
이 인터페이스는 두 가지 주요 부분으로 구성됩니다. 텍스트 풍선이 표시되는 스크롤 가능한 영역과 새로운 풍선을 추가하기 위한 제어 버튼입니다.
BalloonView
ListModel {
id: balloonModel
ListElement {
balloonWidth: 200
}
ListElement {
balloonWidth: 120
}
}
ListView {
id: balloonView
anchors.bottom: controls.top
anchors.bottomMargin: 2
anchors.top: parent.top
delegate: TextBalloon {
anchors.right: index % 2 !== 0 ? parent?.right : undefined
height: 60
rightAligned: index % 2 !== 0
width: balloonWidth
}
model: balloonModel
spacing: 5
width: parent.width
}balloonModel에는 애플리케이션 시작 시 balloonView에 표시될 두 가지 유형이 포함되어 있습니다. balloonView는 TextBalloon 델리게이트 항목의 정렬 방향을 왼쪽 정렬과 오른쪽 정렬 사이에서 번갈아 가며 변경합니다.
컨트롤
Rectangle {
id: controls
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: 1
anchors.right: parent.right
border.width: 2
color: "white"
height: parent.height * 0.15
Text {
anchors.centerIn: parent
text: qsTr("Add another balloon")
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: {
balloonModel.append({"balloonWidth": Math.floor(Math.random() * 200 + 100)})
balloonView.positionViewAtIndex(balloonView.count -1, ListView.End)
}
onEntered: {
parent.color = "#8ac953"
}
onExited: {
parent.color = "white"
}
}
}UI의 컨트롤 부분에는 마우스가 호버하면 색상이 변하는 MouseArea 가 포함된 사각형이 있습니다. 이 컨트롤 '버튼'은 무작위 너비를 가진 새로운 객체를 모델의 끝에 추가합니다.
© 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.