文章目录
QQuickPaintedItem
1.官方资料
QQuickPaintedItem类提供了一种在QML场景图中使用QPainter API的方法。
QQuickPaintedItem使QPainter API与QML场景图一起使用成为可能。它在场景图中设置了一个纹理矩形,并使用QPainter在纹理上作画。
1) 要编写自己的绘制项,首先要创建QQuickPaintedItem的一个子类,然后实现其惟一的纯虚拟公共函数paint(),该函数实现实际的绘制。绘制将在从0,0到width(),height()的矩形内。
2)调用update()来触发重绘。
3)要使QPainter做抗锯齿渲染,使用setAntialiasing()
4)渲染目标可以是QImage,也可以是使用OpenGL时的QOpenGLFramebufferObject。当渲染目标是一个QImage时,QPainter首先渲染到图像中,然后将内容上传到纹理中。当使用QOpenGLFramebufferObject时,QPainter直接在纹理上作画。
**注意:**重要的是要理解这些项目可能引起的性能影响。
参见QQuickPaintedItem::RenderTarget和QQuickPaintedItem::RenderTarget。
1.1. Public Types
1) enum QQuickPaintedItem::PerformanceHint
flags QQuickPaintedItem::PerformanceHints
此枚举描述了可以启用的标志,以提高QQuickPaintedItem中的呈现性能。默认情况下,没有设置这些标志。
Constant | Value | Description |
---|---|---|
FastFBOResizing | 0x1 | 在一些OpenGL驱动程序实现上,调整FBO的大小可能是一项成本高昂的操作。为了解决这个问题,可以设置这个标志,让QQuickPaintedItem分配一个大的帧缓冲区对象,而不是绘制到它的一个子区域中。这样可以节省调整大小,但需要使用更多内存。请注意,这不是一个常见问题。 |
2) enum QQuickPaintedItem::RenderTarget
渲染目标是QPainter在项目在屏幕上渲染之前绘制的表面。
Constant | Value | Description |
---|---|---|
Image | 0 | 默认值:QPainter使用光栅绘制引擎绘制到QImage中。图像的内容随后需要上载到图形内存,如果项目较大,此操作可能会很慢。此渲染目标允许高质量抗锯齿和快速调整项目大小。 |
FramebufferObject | 1 | QPainter使用GL绘制引擎绘制到QOpenGLFramebufferObject中。由于不需要纹理上传,因此绘制速度更快,但抗锯齿质量不如使用图像。在某些情况下,此渲染目标允许更快的渲染,但如果经常调整项目的大小,则应避免使用它。 |
InvertedYFramebufferObject | 2 | 与上面的FramebufferObject完全一样,除非绘制完成,否则在渲染之前,绘制的图像将围绕x轴翻转,以便最顶部的像素现在位于底部。由于这是使用OpenGL纹理坐标完成的,因此实现此效果的方法比使用画家变换快得多。 |
1.2. Properties
1) fillColor : QColor
背景填充的颜色。默认为Qt::transparent。
2) renderTarget : RenderTarget
Constant | Value | Description |
---|---|---|
Image | 0 | 默认值;QPainter使用光栅绘制引擎绘制到QImage中。图像的内容随后需要上载到图形内存,如果项目较大,此操作可能会很慢。此渲染目标允许高质量抗锯齿和快速调整项目大小。 |
FramebufferObject | 1 | QPainter使用GL绘制引擎绘制到QOpenGLFramebufferObject中。由于不需要纹理上传,因此绘制速度更快,但抗锯齿质量不如使用图像。在某些情况下,此渲染目标允许更快的渲染,但如果经常调整项目的大小,则应避免使用它。 |
InvertedYFramebufferObject | 2 | 与上面的FramebufferObject完全一样,除非绘制完成,否则在渲染之前,绘制的图像将围绕x轴翻转,以便最顶部的像素现在位于底部。由于这是使用OpenGL纹理坐标完成的,因此实现此效果的方法比使用画家变换快得多。 |
3) textureSize : QSize
纹理大小。
改变纹理的大小不会影响paint()中使用的坐标系统。取而代之的是一个比例因子,所以绘画应该仍然发生在0,0到width(),height()。
默认情况下,纹理大小将与此项目相同。
注意:如果项目位于设备像素比不等于1的窗口上,则此缩放因子将隐式应用于纹理大小。
1.3. Public Functions
说明 | 类型 | 函数 |
---|---|---|
构造函数 | QQuickPaintedItem(QQuickItem *parent = nullptr) | |
析构函数 | virtual | ~QQuickPaintedItem() override |
抗锯齿 | bool | antialiasing() const |
void | setAntialiasing(bool enable) | |
填充色 | QColor | fillColor() const |
void | setFillColor(const QColor &) | |
纹理尺寸 | QSize | textureSize() const |
void | setTextureSize(const QSize &size) | |
Mipmapping | bool | mipmap() const |
void | setMipmap(bool enable) | |
不透明绘制 | bool | opaquePainting() const |
void | setOpaquePainting(bool opaque) | |
PerformanceHints | PerformanceHints | performanceHints() const |
void | setPerformanceHint(QQuickPaintedItem::PerformanceHint hint, bool enabled = true) | |
void | setPerformanceHints(QQuickPaintedItem::PerformanceHints hints) | |
RenderTarget | RenderTarget | renderTarget() const |
void | setRenderTarget(QQuickPaintedItem::RenderTarget target) | |
更新 | void | update(const QRect &rect = QRect()) |
paint | virtual void | paint(QPainter *painter) = 0 |
Mipmapping 是一种图像处理技术,它采用一个原始的、高分辨率的纹理图像或映射和过滤器,并在同一个纹理文件中将其扩展为多个分辨率更小的纹理映射。依据不同精度的要求,而使用不同版本的材质图样进行贴图
1.4. Reimplemented Public Functions
说明 | 类型 | 函数 |
---|---|---|
纹理提供者 | virtual bool | isTextureProvider() const override |
virtual QSGTextureProvider * | textureProvider() const override |
1.5. Signals
1) void fillColorChanged()
2) void renderTargetChanged()
3) void textureSizeChanged()
1.6. Reimplemented Protected Functions
1) virtual void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) override
2) virtual void releaseResources() override
3) virtual QSGNode * updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override
2. 案例
2.1. QuickPaintedItem 类
2.1.1. QuickPaintedItem.h
#ifndef QUICKPAINTEDITEM_H
#define QUICKPAINTEDITEM_H
#include <QPainterPath>
#include <QtQuick>
class QuickPaintedItem : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(bool draw READ isDraw WRITE setDraw NOTIFY drawChanged)
Q_PROPERTY(bool antialias READ isAntialias WRITE setAntialias NOTIFY antialiasChanged)
public:
QuickPaintedItem(QQuickItem *parent = 0);
void paint(QPainter *painter) override;
Q_INVOKABLE void mousePress (qreal x, qreal y) ;
Q_INVOKABLE void mouseMove (qreal x, qreal y) ;
Q_INVOKABLE void mouseRelease (qreal x, qreal y) ;
bool isDraw() const;
void setDraw(bool newDraw);
bool isAntialias() const;
void setAntialias(bool newAntialias);
private:
signals:
void drawChanged();
void antialiasChanged();
private:
bool draw;
QPainterPath m_path;
QPolygonF m_poly;
};
#endif
2.1.2. QuickPaintedItem.cpp
#include "QuickPaintedItem.h"
#include <QDebug>
#define qout if( 1 ) qDebug()
static QPointF startPoint, lastPoint;
QuickPaintedItem::QuickPaintedItem(QQuickItem *parent)
: QQuickPaintedItem(parent)
, draw(false)
{
}
void QuickPaintedItem::paint(QPainter *painter)
{
painter->drawPath(m_path);
painter->drawPolyline(m_poly);
if(startPoint.isNull() || lastPoint.isNull())
return;
if(draw){
painter->setPen(Qt::red);
painter->drawLine(startPoint,lastPoint);
}
}
void QuickPaintedItem::mousePress(qreal x, qreal y)
{
startPoint.rx() = x;
startPoint.ry() = y;
if(draw){
m_path.addRect(x-1,y-1,2,2);
m_poly.append(startPoint);
update();
}
}
void QuickPaintedItem::mouseMove(qreal x, qreal y)
{
lastPoint.rx() = x;
lastPoint.ry() = y;
update();
}
void QuickPaintedItem::mouseRelease(qreal x, qreal y)
{
if(draw){
lastPoint.rx() = x;
lastPoint.ry() = y;
}else{
}
update();
}
bool QuickPaintedItem::isDraw() const
{
return draw;
}
void QuickPaintedItem::setDraw(bool newDraw)
{
if(newDraw==false) {
startPoint = lastPoint = QPointF();
m_path.addPolygon(m_poly);
m_path.closeSubpath();
m_poly = QPolygonF();
update();
}
if (draw == newDraw)
return;
draw = newDraw;
emit drawChanged();
}
bool QuickPaintedItem::isAntialias() const
{
return antialiasing();
}
void QuickPaintedItem::setAntialias(bool newAntialias)
{
if (antialiasing() == newAntialias)
return;
setAntialiasing(newAntialias);
emit antialiasChanged();
}
2.2. main.qml
import QtQuick 2.0
import QtQml.Models 2.15
import MyQuickPaintedItem 1.0
Item {
height: 480
width: 320
QuickPaintedItem {
id: drawer
anchors.fill: parent
antialias: true
MouseArea{
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled:true
onPressed: {
if(mouse.button == Qt.LeftButton){
drawer.draw = true;
parent.mousePress(mouseX,mouseY)
}
else{
drawer.draw = false;
}
}
onPositionChanged: {
parent.mouseMove(mouseX,mouseY)
}
onReleased: {
if(mouse.button == Qt.LeftButton)
parent.mouseRelease(mouseX,mouseY)
}
}
}
}
2.3. main.cpp
#include <QApplication>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "QuickPaintedItem.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQuickView view;
qmlRegisterType<QuickPaintedItem>("MyQuickPaintedItem",1,0,"QuickPaintedItem");
view.setSource(QUrl(QStringLiteral("qrc:/painteditem/main.qml")));
view.show();
return app.exec();
}