场景图 - 彩绘项目

展示如何实现基于QPainter 的自定义场景图项。

Painted Item 示例展示了如何使用 QML 场景图框架,使用QPainter 实现自定义场景图项。

QQuickPaintedItem 类是从QQuickItem 派生的一个类,用于使用QPainter 接口实现自定义 QML 场景图项。

该示例包括一个项目类和一个使用项目的 QML 文件。TextBalloon 类表示扩展到QQuickPaintedItem 的单个文本气球,textballoons.qml 文件用于加载包含 TextBalloon QML 类型的模块并显示文本气球。

我们将首先集中讨论TextBalloon 类,然后继续讨论textballoons.qml 文件。有关如何为 QML 模块实现插件的示例,请参阅《编写扩展插件》(Writing an Extension Plugin)。

文本气球类声明

TextBalloon 类继承于QQuickPaintedItemQQuickPaintedItem 是 QML 场景图框架中所有基于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 ,你必须实现 QQuickPaintedIem 的纯虚函数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 文件

界面由两大部分组成。包含文本气球的可滚动区域和用于添加新气球的控制按钮。

气球视图
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
}

在应用程序启动时,气球模型包含两种类型,将由气球视图显示。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"
        }
    }
}

用户界面的控件部分包含一个带有MouseArea 的矩形,当鼠标悬停在该矩形上时,它的颜色会发生变化。该控件 "按钮 "会在模型末尾添加一个宽度随机的新对象。

示例项目 @ code.qt.io

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