在Qt帮助文档中搜索“Scene Graph - Painted Item ”可以看到,原来的代码是写成QML调用C++插件的方式。由于插件方式对不熟悉的同学来说,可能要踩一些坑,其实可以放在一个工程里,通过qmlRegisterType的方式进行注册,然后在qml中进行调用。
QQuickPaintedItem继承自QQuickItem,而QQuickItem就是Qml中的Item。
QQuickPaintedItem通过重载paint函数,就可以使用QPainter绘制。
自定义的QQuickPaintedItem子类需要注册到Qml中才能使用,注册类型或者注册实例都可以。
textballoon.h
#ifndef TEXTBALLOON_H
#define TEXTBALLOON_H
#include <QtQuick>
class TextBalloon : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(bool rightAligned READ isRightAligned WRITE setRightAligned NOTIFY rightAlignedChanged)
public:
TextBalloon(QQuickItem *parent = nullptr);
void paint(QPainter *painter);
bool isRightAligned();
void setRightAligned(bool rightAligned);
private:
bool rightAligned;
signals:
void rightAlignedChanged();
};
#endif
textballoon.cpp
#include "textballoon.h"
TextBalloon::TextBalloon(QQuickItem *parent)
: QQuickPaintedItem(parent)
, rightAligned(false)
{
}
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, static_cast<int>(itemSize.width()), static_cast<int>(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);
}
}
bool TextBalloon::isRightAligned()
{
return this->rightAligned;
}
void TextBalloon::setRightAligned(bool rightAligned)
{
this->rightAligned = rightAligned;
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlEngine>
#include "textballoon.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
qmlRegisterType<TextBalloon>("TextBalloonPlugin", 1, 0, "TextBalloon");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import TextBalloonPlugin 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
//! [0]
ListModel {
id: balloonModel
ListElement {
balloonWidth: 200
}
ListElement {
balloonWidth: 120
}
}
ListView {
anchors.bottom: controls.top
anchors.bottomMargin: 2
anchors.top: parent.top
id: balloonView
delegate: TextBalloon {
anchors.right: index % 2 == 0 ? undefined : parent.right
height: 60
rightAligned: index % 2 == 0 ? false : true
width: balloonWidth
}
model: balloonModel
spacing: 5
width: parent.width
}
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: "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"
}
}
}
}
运行效果:
代码地址:https://github.com/xiaozia/blogs/tree/master/qml/20190729/TextBalloonDemo
参考:
Qt Quick实现的涂鸦程序 https://blog.csdn.net/u010002704/article/details/41514371
Qml组件化编程7-自绘组件 https://blog.csdn.net/d759378563/article/details/90384469