• qml实现路径绘制且可编辑


    本文章示例要实现的功能是qml工程中实现圆形、矩形、多边形和直尺的绘制,并且可以通过控制点来改变路径,效果如图:
    在这里插入图片描述

    通过继承QQuickPaintedItem

    qml工程中进行绘制除了使用Canvas,还有一种方法就是继承QQuickPaintedItem了,然后重写其虚函数paint(),调用update()来触发绘制。对于该类更详细的描述我就不介绍了,大家可以自己查阅。

    示例代码

    定义Annotation类,然后继承自QQuickPaintedItem

    #pragma once
    
    #include <QPainterPath>
    #include <QQuickPaintedItem>
    #include <vector>
    #include <QPoint>
    #include <memory>
    #include "basedraw.h"
    
    struct moveDraw
    {
    	std::shared_ptr<BaseDraw> pDraw;
    	int ptIndex;
    
    	void reset()
    	{
    		pDraw.reset();
    		ptIndex = -1;
    	}
    	bool isEmpty()
    	{
    		return pDraw.get() == nullptr;
    	}
    };
    
    class Annotation : public QQuickPaintedItem
    {
        Q_OBJECT
        Q_ENUMS(EM_DRAW_TYPE)
        Q_PROPERTY(EM_DRAW_TYPE drawType READ drawType WRITE setDrawType)
    public:
        enum EM_DRAW_TYPE{
            ELLIPSE,//椭圆
            RECTANGLE,//矩形
            POLYGON,//多边形(直线型)
            SPLINE,//多边形(曲线型)
            MEASUREMENT,//直尺
            MAX
        };
    
        Annotation(QQuickPaintedItem *parent = nullptr);
    
    protected:
        void paint(QPainter *painter);
    
    public slots:
        void slotCompare();
    
    public:
        Q_INVOKABLE void mousePress(qreal x, qreal y);
        Q_INVOKABLE void mouseMove(qreal x, qreal y);
        Q_INVOKABLE void mouseRelease(qreal x, qreal y);
    	Q_INVOKABLE void undo();
    
        EM_DRAW_TYPE drawType();
        void setDrawType(const EM_DRAW_TYPE& type);
    
    private:
        EM_DRAW_TYPE _drawType = MAX;//当前绘制类型
    	std::vector<std::shared_ptr<BaseDraw>> _draws;//保存的图形
        std::shared_ptr<BaseDraw> _pCurDraw = nullptr;
    	moveDraw _moveDraw;
    };
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    然后重写其paint()虚函数,实现绘制功能

    void Annotation::paint(QPainter *painter)
    {
    	painter->setRenderHint(QPainter::Antialiasing);
    	painter->save();
    	for (auto pDraw : _draws)
    	{
    		pDraw->paint(painter);
    	}
    	if (_pCurDraw)
    		_pCurDraw->paint(painter);
    
    	painter->restore();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    其中BaseDraw是绘图的基类,ellipseDrawmeasurementDrawpolygonDrawrectangeDrawsplineDraw继承于BaseDraw,分别实现绘制不同的功能。关系如图:
    在这里插入图片描述
    BaseDraw基类代码:

    #ifndef BASEDRAW_H
    #define BASEDRAW_H
    
    #include <QObject>
    #include <QPainterPath>
    #include <QPainter>
    #include <vector>
    #include <QPoint>
    
    class BaseDraw : public QObject
    {
        Q_OBJECT
    public:
        explicit BaseDraw(QObject *parent = 0);
    
    signals:
        void sigCompare();
    
    public slots:
    
    public:
        virtual void mousePress(qreal x, qreal y);
        virtual void mouseMove(qreal x, qreal y);
        virtual void mouseRelease(qreal x, qreal y);
    
    protected:
        virtual void pointsChanged(){}
        virtual QPainterPath getCurrentPath(const std::vector<QPoint>& coords){ return QPainterPath();}
    
    public:
        void reset();
        virtual void paint(QPainter *painter)=0;
        std::vector<QPoint> getPoints(){return _pts;}
        void setPoints(const std::vector<QPoint>&);
    	void setPoint(int idx, int x, int y);
        bool closed() { return _finished; }
    
    protected:
        std::vector<QPoint> _pts;//当前点
        QPainterPath _currentPath;
        QPolygonF _polys;
        QPoint _startPt,_lastPt,falsePt;
        bool _pressed =false;//是否按下
        bool _finished = true;//是否闭合
        bool _startPtLight = false;//起始点是否高亮
        QString _type = "spline";//多边形类型
    };
    
    #endif // BASEDRAW_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    BaseDraw基类中有个paint()纯虚函数,继承于它的几个子类都必须重写该虚函数用于实现不同的绘制工作,且该paint()都是在Annotation类的paint()处被调用。
    其它类的代码和详细的实现我就不全部展示出来了,我只是提供我的实现思路,我会给出代码链接,需要代码的朋友可以去下载。

    注册

    在cpp中,我们对Annotation类进行注册

    qmlRegisterType<Annotation>("df.annotation", 1, 0, "Annotation");
    
    • 1

    qml中调用

    import QtQuick 2.7
    import QtQuick.Window 2.2
    import an.utility 1.0
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        Item{
            anchors.fill: parent
            Rectangle{
                id:id_rect_btn
                width: 60
                anchors.top: parent.top
                anchors.bottom: parent.bottom
                anchors.left:parent.left
                color: "#d9d9d9"
                Column{
                    property var ck_name: ""
                    id:id_com
                    spacing: 10
                    CButton{
                        img_source:"qrc:/resource/ellipse.png"
                        isChecked:id_com.ck_name === "ellipse"
                        onClicked: {
                            id_com.ck_name = "ellipse"
                            id_annotation.drawType = Annotation.ELLIPSE
                        }
                    }
                    CButton{
                        img_source:"qrc:/resource/rectangle.png"
                        isChecked:id_com.ck_name === "rectangle"
                        onClicked: {
                            id_com.ck_name = "rectangle"
                            id_annotation.drawType = Annotation.RECTANGLE
                        }
                    }
                    CButton{
                        img_source:"qrc:/resource/poly.png"
                        isChecked:id_com.ck_name === "poly"
                        onClicked: {
                            id_com.ck_name = "poly"
                            id_annotation.drawType = Annotation.POLYGON
                        }
                    }
                    CButton{
                        img_source:"qrc:/resource/spline.png"
                        isChecked:id_com.ck_name === "spline"
                        onClicked: {
                            id_com.ck_name = "spline"
                            id_annotation.drawType = Annotation.SPLINE
                        }
                    }
                    CButton{
                        img_source:"qrc:/resource/measure.png"
                        isChecked:id_com.ck_name === "measure"
                        onClicked: {
                            id_com.ck_name = "measure"
                            id_annotation.drawType = Annotation.MEASUREMENT
                        }
                    }
                }
            }
            Annotation
            {
                id: id_annotation
                anchors.left: id_rect_btn.right
                anchors.top: parent.top
                anchors.bottom: parent.bottom
                anchors.right: parent.right
    
                MouseArea
                {
                    anchors.fill: parent
                    hoverEnabled: true
                    onPressed: id_annotation.mousePress(mouse.x, mouse.y)
                    onPositionChanged:id_annotation.mouseMove(mouse.x, mouse.y)
                    onReleased: id_annotation.mouseRelease(mouse.x, mouse.y)
                    focus: true
                    Keys.enabled: true
                    Keys.onPressed: {
                        if (event.matches(StandardKey.Undo))
                        {
                            id_annotation.undo()
                        }
                    }
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    CButton是我自定义的按钮控件,大家可以无视。。。

    源代码链接

  • 相关阅读:
    用Rust开发一个mybatis的逆向工具
    【echarts 】设置datazoom 允许使用鼠标滚轮滚动图表
    [HDLBits] Exams/m2014 q4k
    Linux下的触摸屏驱动编程
    .NET 实现虚拟WebShell第2课之AuthenticationFilter
    游戏出海,全球化运营
    Spark 离线开发框架设计与实现
    SW-2运行结果
    Redis单线程
    PHP+MySQL制作简单动态网站(附详细注释+源码)
  • 原文地址:https://blog.csdn.net/qq_26611129/article/details/125483296