Qt使用C++封装qml自定义图形控件(QQuickPaintedItem)

C++封装qml自定义图形控件

  • QtWidget、qml简介
  • 通过继承QQuickPaintedItem封装控件
    • 描述
    • 公用接口定义
    • 代码示例
    • 效果图

QtWidget、qml简介

Qt提供了2套UI模式,分别是c++为主的代表Qt Widget,还有一套是qt quick。
QtWidget已经相对很稳定了,控件丰富,所以一些大型项目也可得心应手。
qml做的界面比较美观,可以简单的写出一些炫酷的动画和特效,对触屏支持比较友好。比较适合做移动端开发,但是对于一些大型hua项目,界面复杂的个人认为还是用QtWidget好一点。qt quick默认是用opengl做图形渲染引擎。一般qquick项目,qml写界面,c++做功能后端。
今天我们要讲的是如何使用c++给qml封装自定义的图形控件。

通过继承QQuickPaintedItem封装控件

描述

QQuickPaintedItem使QPainter API与QML场景图一起使用成为可能。它在场景图中设置一个带纹理的矩形,并使用QPainter在纹理上绘制。渲染目标可以是一个QImage,或者在使用OpenGL时,是一个QOpenGLFramebufferObject。当渲染目标是一个QImage时,QPainter首先渲染到图像中,然后将内容上载到纹理中。当使用QOpenGLFramebufferObject时,QPainter直接在纹理上绘制。调用update()触发重绘。
若要启用QPanter进行抗锯齿渲染,请使用setAntialiasing()。
要编写自己绘制的项,首先要创建QQuickPaintedItem的子类,然后从实现其唯一纯虚拟公共函数paint()开始,该函数实现实际绘制。绘制将位于从0,0到width(),height()的矩形内。

公用接口定义

QQuickPaintedItem(QQuickItem *parent = Q_NULLPTR)
virtual ~QQuickPaintedItem()
bool antialiasing() const
QColor fillColor() const
bool mipmap() const
bool opaquePainting() const
virtual void paint(QPainter *painter) = 0
PerformanceHints performanceHints() const
RenderTarget renderTarget() const
void setAntialiasing(bool enable)
void setFillColor(const QColor &)
void setMipmap(bool enable)
void setOpaquePainting(bool opaque)
void setPerformanceHint(PerformanceHint hint, bool enabled = true)
void setPerformanceHints(PerformanceHints hints)
void setRenderTarget(RenderTarget target)
void setTextureSize(const QSize &size)
QSize textureSize() const
void update(const QRect &rect = QRect())

这次起到关键作用的函数是主角 virtual void paint(QPainter *painter)=0,通过重写虚函数paint,实现要画的内容。

代码示例

下面实现一个图片显示的控件,滑动鼠标滚轮可实现图片的放大和缩小。

定义类XImageView,继承QQuickPaintedItem

#ifndef XIMAGEVIEW_H
#define XIMAGEVIEW_H

#include 
#include 
#include 

class QPainter;
class XImageView : public QQuickPaintedItem
{
    Q_OBJECT

    Q_PROPERTY(QImage mImage READ getImage WRITE setImage)
    Q_PROPERTY(QString fileUrl READ getFileUrl WRITE setFileUrl)
    Q_PROPERTY(int mWidth READ getWidth WRITE setWidth)
    Q_PROPERTY(int mHeight READ getHeight WRITE setHeight)

public:
    XImageView(QQuickItem *parent = 0);
    virtual ~XImageView();

    virtual void paint(QPainter *painter);

    QImage getImage() const;
    void setImage(QImage img);

    QString getFileUrl() const;
    void setFileUrl(QString url);

    int getWidth() const;
    void setWidth(int w);

    int getHeight() const;
    void setHeight(int h);

    Q_INVOKABLE void zoomDraw(float z = 1.0f);

private:
   QImage mImage;
   QString fileUrl;
   int mWidth;
   int mHeight;
   float mZoom;
};

#endif // XIMAGEVIEW_H

paint函数重写实现自绘

void XImageView::paint(QPainter *painter)
{
    if (painter == nullptr)
    {
        return;
    }
    if(mImage.isNull())
    {
        if(!fileUrl.isEmpty())
        {
            if(!mImage.load(fileUrl))
            {
                qDebug("load image file failed!");
                return;
            }
        }else
        {
            qDebug("file is not exsit!");
            return;
        }
    }

    QImage tempImage = mImage.scaled(mWidth*mZoom,mHeight*mZoom,Qt::KeepAspectRatio);

    painter->setRenderHint(QPainter::Antialiasing, true);
    painter->setRenderHint(QPainter::HighQualityAntialiasing, true);
    painter->setRenderHint(QPainter::SmoothPixmapTransform, true );
    painter->drawImage(0,0, tempImage);
}

注意:调用之前要先注册qml类型。

    int verMajor = 1;
    int verMinor = 0;

    qmlRegisterType<XImageView>("custom.qimi.image",verMajor,verMinor,"XImageView");

qml调用示例

import QtQuick 2.9
import QtQuick.Window 2.2

import custom.qimi.image 1.0

Window {
    visible: true
    width: 480
    height: 800
    title: qsTr("QQuickPaintedItem Plugin 费马程序员 QQ:2558950565")

    property double zoomVlaue: 1.0
    signal drawImage()

    Rectangle
    {
        id: image
        color: "transparent"
        border.color: "red"
        anchors
        {
            margins: 0
            centerIn: parent
            fill: parent
        }  
    }

    XImageView
    {
        id: ximageView
        width: parent.width
        height: parent.height
        mWidth: parent.width
        mHeight: parent.height
        fileUrl: ":/image/mmm.jpg"
    }

    MouseArea
    {
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton
        onClicked: {
            if(mouse.button === Qt.LeftButton)
            {
                drawImage();
            }
        }
        onWheel: {
            var m_value = wheel.angleDelta.y/120;
            if(m_value>0)
            {
                if(zoomVlaue<1.0){
                zoomVlaue += 0.1;
                }
            }else
            {
                if(zoomVlaue>0.0){
                zoomVlaue -= 0.1;
                }
            }
            console.log("wheel event=,zoom=",m_value,zoomVlaue);
            ximageView.zoomDraw(zoomVlaue);
        }
    }

    onDrawImage: {
        console.log("mouse clicked!");
        ximageView.zoomDraw();
    }
}

效果图

滑动鼠标中间滚轮实现放大缩小:

结语:通过以上方法,我们可以实现qml各种不同控件的自定义。
完整代码示例:示例代码下载链接

作者:费码程序猿
欢迎技术交流:QQ:255895056
转载请注明出处,如有不当欢迎指正

你可能感兴趣的:(qml,qt,c++,qml)