场景图 - 绘制项

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

绘制项示例展示了如何使用 QML 场景图框架利用 QPainter 来实现自定义场景图项目。

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

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

我们将首先关注 TextBalloon 类,然后继续介绍 textballoons.qml 文件。有关如何实现 QML 模块的插件示例,请参阅 编写扩展插件

TextBalloon 类声明

TextBalloon 类继承自 QQuickPaintedItemQQuickPaintedItem 是所有基于 QPainter 的 QML 场景图框架中项目的基类。

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 文件

接口包括两个主要部分。带有文本气球的可滚动区域以及用于添加新气球的控件按钮。

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

气球模型在应用程序启动时包含两种类型,这些类型将由气球视图显示。气球视图在左对齐和右对齐之间交替 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 的控件部分包含一个带有 鼠标区域 的矩形,鼠标悬停在上方时颜色会改变。这个“按钮”控件将一个具有随机宽度的新对象添加到模型的末尾。

示例项目 @ code.qt.io

© 2024 Qt 公司有限公司。此处包含的文档贡献版权属于其各自所有者。本提供的文档是根据由自由软件基金会发布的 GNU 自由文档许可协议版本 1.3 的条款授权的。Qt 及其相关商标是芬兰和/或其他国家的 Qt 公司的商标。所有其他商标归其各自所有者所有。