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中的呈现性能。默认情况下,没有设置这些标志。

ConstantValueDescription
FastFBOResizing0x1在一些OpenGL驱动程序实现上,调整FBO的大小可能是一项成本高昂的操作。为了解决这个问题,可以设置这个标志,让QQuickPaintedItem分配一个大的帧缓冲区对象,而不是绘制到它的一个子区域中。这样可以节省调整大小,但需要使用更多内存。请注意,这不是一个常见问题。

2) enum QQuickPaintedItem::RenderTarget
渲染目标是QPainter在项目在屏幕上渲染之前绘制的表面。

ConstantValueDescription
Image0默认值:QPainter使用光栅绘制引擎绘制到QImage中。图像的内容随后需要上载到图形内存,如果项目较大,此操作可能会很慢。此渲染目标允许高质量抗锯齿和快速调整项目大小。
FramebufferObject1QPainter使用GL绘制引擎绘制到QOpenGLFramebufferObject中。由于不需要纹理上传,因此绘制速度更快,但抗锯齿质量不如使用图像。在某些情况下,此渲染目标允许更快的渲染,但如果经常调整项目的大小,则应避免使用它。
InvertedYFramebufferObject2与上面的FramebufferObject完全一样,除非绘制完成,否则在渲染之前,绘制的图像将围绕x轴翻转,以便最顶部的像素现在位于底部。由于这是使用OpenGL纹理坐标完成的,因此实现此效果的方法比使用画家变换快得多。

1.2. Properties

1) fillColor : QColor
背景填充的颜色。默认为Qt::transparent。

2) renderTarget : RenderTarget

ConstantValueDescription
Image0默认值;QPainter使用光栅绘制引擎绘制到QImage中。图像的内容随后需要上载到图形内存,如果项目较大,此操作可能会很慢。此渲染目标允许高质量抗锯齿和快速调整项目大小。
FramebufferObject1QPainter使用GL绘制引擎绘制到QOpenGLFramebufferObject中。由于不需要纹理上传,因此绘制速度更快,但抗锯齿质量不如使用图像。在某些情况下,此渲染目标允许更快的渲染,但如果经常调整项目的大小,则应避免使用它。
InvertedYFramebufferObject2与上面的FramebufferObject完全一样,除非绘制完成,否则在渲染之前,绘制的图像将围绕x轴翻转,以便最顶部的像素现在位于底部。由于这是使用OpenGL纹理坐标完成的,因此实现此效果的方法比使用画家变换快得多。

3) textureSize : QSize
纹理大小。
改变纹理的大小不会影响paint()中使用的坐标系统。取而代之的是一个比例因子,所以绘画应该仍然发生在0,0到width(),height()。
默认情况下,纹理大小将与此项目相同。
注意:如果项目位于设备像素比不等于1的窗口上,则此缩放因子将隐式应用于纹理大小。

1.3. Public Functions

说明类型函数
构造函数QQuickPaintedItem(QQuickItem *parent = nullptr)
析构函数virtual~QQuickPaintedItem() override
抗锯齿boolantialiasing() const
voidsetAntialiasing(bool enable)
填充色QColorfillColor() const
voidsetFillColor(const QColor &)
纹理尺寸QSizetextureSize() const
voidsetTextureSize(const QSize &size)
Mipmappingboolmipmap() const
voidsetMipmap(bool enable)
不透明绘制boolopaquePainting() const
voidsetOpaquePainting(bool opaque)
PerformanceHintsPerformanceHintsperformanceHints() const
voidsetPerformanceHint(QQuickPaintedItem::PerformanceHint hint, bool enabled = true)
voidsetPerformanceHints(QQuickPaintedItem::PerformanceHints hints)
RenderTargetRenderTargetrenderTarget() const
voidsetRenderTarget(QQuickPaintedItem::RenderTarget target)
更新voidupdate(const QRect &rect = QRect())
paintvirtual voidpaint(QPainter *painter) = 0

Mipmapping 是一种图像处理技术,它采用一个原始的、高分辨率的纹理图像或映射和过滤器,并在同一个纹理文件中将其扩展为多个分辨率更小的纹理映射。依据不同精度的要求,而使用不同版本的材质图样进行贴图

1.4. Reimplemented Public Functions

说明类型函数
纹理提供者virtual boolisTextureProvider() 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();
}
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐