美文网首页my-QT专栏
QT 自定义绘制图形Item+QGraphicsView

QT 自定义绘制图形Item+QGraphicsView

作者: c之气三段 | 来源:发表于2021-09-05 11:27 被阅读0次

    .h

    #ifndef SHAPEITEM_H
    #define SHAPEITEM_H
    
    #include <QGraphicsItem>
    #include <QPen>
    
    class ShapeItem : public QGraphicsItem
    {
    public:
        explicit ShapeItem(QGraphicsItem  *parent = nullptr);
        ~ShapeItem();
        void setShapeItem(int x1,int y1,int w,int h,int angle);
        void setPen(const QPen &pen);
    public:
        //绘图区域
        virtual QRectF boundingRect() const override;
        //绘图函数
        virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
    private:
        int m_x1,m_y1,m_w,m_h;
        int m_angle;
        QPen m_pen;
    };
    
    #endif // SHAPEITEM_H
    
    

    .cpp

    #include "ShapeItem.h"
    
    #include <QPainter>
    #include<QDebug>
    ShapeItem::ShapeItem(QGraphicsItem  *parent) : QGraphicsItem(parent)
    {
    
    }
    
    ShapeItem::~ShapeItem()
    {
    
    }
    
    void ShapeItem::setShapeItem(int x1, int y1, int w, int h,int angle)
    {
        m_x1=x1;
        m_y1=y1;
        m_w=w;
        m_h=h;
        m_angle=angle;
    }
    
    void ShapeItem::setPen(const QPen& pen)
    {
        m_pen=pen;
    }
    
    QRectF ShapeItem::boundingRect() const
    {
        return QRectF(m_x1, m_y1,m_w, m_h);
    }
    
    void ShapeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    {
        // 矩形
        QRectF rect(m_x1, m_y1, m_w, m_h);
        // 起始角度
        int startAngle = 0;
        // 跨越度数
        double spanAngle = m_angle * 16;
    
        // 反走样
        painter->setRenderHint(QPainter::Antialiasing, true);
    
        // 设置画笔颜色、宽度
        painter->setPen(m_pen);
    
        // 绘制弧线
        painter->drawPie(rect, startAngle, spanAngle);
    }
    
    

    QGraphicsView的使用

    .h

    #ifndef CANVAS_H
    #define CANVAS_H
    
    #include "ShapeItem.h"
    
    #include <QWidget>
    #include<QGraphicsView>
    #include <QHBoxLayout>
    struct Data
    {
       QString legend;
       QString xLeble;
       QString yLeble;
       QVector<QPointF> points;
    };
    struct Rgb
    {
        int r;
        int g;
        int b;
    };
    class Canvas : public QWidget
    {
        Q_OBJECT
    public:
        explicit Canvas(QWidget *parent = nullptr);
        ~Canvas();
        void draw();
        //规范坐标
        void setRange(float cormin,float cormax);
        //数据源
        void addLine(const QString &legend,const QString &xLeble,const QString &yLeble,const QVector<QPointF> &points);
        void setTitle(const QString& title);
        //跨越度数
        void setStepAngle(double angle);
        //清空画布中的线
        void clearLine();
        void test();
    private:
        //刷新属性
        void resetAttribute();
        //创建坐标
        void createHorizontalAxis();
        void createCircleAxis();
        //添加字符
        void setText(int x,int y,const QString &strText,int fontSize);
        //绘制曲线
        void curvePlotting();
        //颜色
        void addAllRgb(int rgbCount);
        void creatRgb(int *rgb);
    
    signals:
    
    private:
        QGraphicsView *m_pGraphicView;
        QHBoxLayout *m_pHBoxLayout;
        QGraphicsScene *m_pScene;
        QPen *m_pPen;
        const float m_pi=3.14159f;
        float m_interval;
        int m_halfWidth;
        int m_halfHeight;
        int m_bottomPointX;
        int m_angle;
        int m_scaleWidth;
        double m_stepAngle;
        //坐标
        int m_cormax,m_cormin,m_cornumber;
        //曲线数据
        QVector<Data>m_data;
        QString m_title;
        //rgb
        QList<Rgb>m_rgbs;
        QList<ShapeItem*>m_listShaps;
        // QWidget interface
    protected:
        void resizeEvent(QResizeEvent* event);
    };
    
    #endif // CANVAS_H
    

    .cpp

    #include "Canvas.h"
    #include"QDebug"
    #include <QGraphicsItem>
    #include <QResizeEvent>
    #include <QTime>
    Canvas::Canvas(QWidget *parent) : QWidget(parent)
    {
       //构建画布
       m_pGraphicView=new QGraphicsView;
       m_pGraphicView->setRenderHint(QPainter::Antialiasing, true);
       m_pGraphicView->setStyleSheet("background-color:rgb(240, 240, 240)");
       m_pGraphicView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
       m_pGraphicView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
       m_pHBoxLayout=new QHBoxLayout;
       m_pHBoxLayout->addWidget(m_pGraphicView);
       this->setLayout(m_pHBoxLayout);
       m_pHBoxLayout->setContentsMargins(0,0,0,0);
       //获取一半宽度
       m_halfWidth=m_pGraphicView->width()/2;
       m_halfHeight=m_pGraphicView->height()/2;
       //构建场景
       m_pScene = new QGraphicsScene();
       m_pGraphicView->setScene(m_pScene);
       m_pScene->setSceneRect(-m_halfWidth, -m_halfHeight, m_pGraphicView->width(), m_pGraphicView->height());
       m_pGraphicView->setScene(m_pScene);
       //画笔
       m_pPen=new QPen;
       setRange(0,40);
    }
    
    Canvas::~Canvas()
    {
        delete m_pPen;
        qDeleteAll(m_listShaps);
        m_listShaps.clear();
        delete m_pScene;
        delete m_pHBoxLayout;
        delete m_pGraphicView;
    }
    
    void Canvas::draw()
    {
        qDeleteAll(m_listShaps);
        m_listShaps.clear();
        createHorizontalAxis();
        curvePlotting();
    }
    
    void Canvas::resetAttribute()
    {
        m_halfWidth=m_pGraphicView->width()/2;
        m_halfHeight=m_pGraphicView->height()/2;
        m_pScene->setSceneRect(-m_halfWidth, -m_halfHeight, m_pGraphicView->width(), m_pGraphicView->height());
    }
    
    void Canvas::createHorizontalAxis()
    {
        m_pScene->clear();
        //最右侧点的x坐标
        m_bottomPointX=m_halfHeight-40;
        m_scaleWidth=m_bottomPointX/20;
        m_bottomPointX=m_scaleWidth*20;
        setText(0,-m_bottomPointX-35,m_title,15);
        m_pPen->setWidth(4);
        m_pPen->setColor(QColor(60, 60, 60));
        QGraphicsLineItem *lineItem = m_pScene->addLine(QLineF(0,0,m_bottomPointX ,0));
        lineItem->setPen(*m_pPen);
        createCircleAxis();
        float text=m_cormin;
        m_interval=(float)((m_cormax-m_cormin)/m_cornumber);
        for (int i = 0,x=0; i <= 20; ++i)
        {
            if(i%5==0)
            {
                lineItem=m_pScene->addLine(QLineF(x,-8,x,0));
                m_pPen->setWidth(4);
                m_pPen->setColor(QColor(60,60, 60));
                lineItem->setPen(*m_pPen);
    
                setText(x,12, QString("%1").arg(text),10);
                text+=m_interval;
            }
            else
            {
                lineItem=m_pScene->addLine(QLineF(x,-6,x,0));
                m_pPen->setWidth(2);
                m_pPen->setColor(QColor(120,120,120));
                lineItem->setPen(*m_pPen);
            }
            x+=m_scaleWidth;
        }
    }
    
    void Canvas::createCircleAxis()
    {
        int r=m_bottomPointX;
        int interval=m_scaleWidth*5;
        ShapeItem *pShapeItem=nullptr;
        for (int i = 0; i <=r; i+=interval)
        {
            m_pPen->setWidth(2);
            m_pPen->setColor(QColor(120,120,120));
            pShapeItem=new ShapeItem;
            m_listShaps.append(pShapeItem);
            if(i==r)
            {
                m_pPen->setWidth(4);
                m_pPen->setColor(QColor(60,60,60));
                pShapeItem->setPen(*m_pPen);
                pShapeItem->setShapeItem(-i,-i,i*2,i*2,m_stepAngle);
                m_pScene->addItem(pShapeItem);
            }
            else
            {
                pShapeItem->setPen(*m_pPen);
                pShapeItem->setShapeItem(-i,-i,i*2,i*2,m_stepAngle);
                m_pScene->addItem(pShapeItem);
            }
        }
        int minimumR=interval;
        QGraphicsLineItem *lineItem=nullptr;
        for (int angle = 0,i=0; angle >= -m_stepAngle; angle-=5,i++)
        {
            int x1=(int)r*cosf(angle*m_pi/180);
            int y1=(int)r*sinf(angle*m_pi/180);
            if(i%6!=0)
            {
                int x2=(int)(r-6)*cosf(angle*m_pi/180);
                int y2=(int)(r-6)*sinf(angle*m_pi/180);
                lineItem=m_pScene->addLine(QLineF(x1,y1,x2,y2));
                m_pPen->setWidth(2);
                m_pPen->setColor(QColor(120,120,120));
                lineItem->setPen(*m_pPen);
            }
            else
            {
                if(!(angle==0||angle==-m_stepAngle))
                {
                    int minX=(int)minimumR*cosf(angle*m_pi/180);
                    int minY=(int)minimumR*sinf(angle*m_pi/180);
                    lineItem=m_pScene->addLine(QLineF(x1,y1,minX,minY));
                    m_pPen->setWidth(2);
                    m_pPen->setColor(QColor(120,120,120));
                    lineItem->setPen(*m_pPen);
                }
                int x2=(int)(r-8)*cosf(angle*m_pi/180);
                int y2=(int)(r-8)*sinf(angle*m_pi/180);
                lineItem=m_pScene->addLine(QLineF(x1,y1,x2,y2));
                m_pPen->setWidth(4);
                m_pPen->setColor(QColor(60,60,60));
                lineItem->setPen(*m_pPen);
                if(-angle>=360){break;}
                int textX=(int)(r+15)*cosf(angle*m_pi/180);
                int textY=(int)(r+15)*sinf(angle*m_pi/180);
                setText(textX,textY,QString::number(-angle),10);
            }
        }
    }
    
    void Canvas::setText(int x,int y,const QString &strText,int fontSize)
    {
        m_pPen->setWidth(1);
        m_pPen->setColor(QColor(60, 60, 60));
        QGraphicsSimpleTextItem *textItem=m_pScene->addSimpleText(strText,QFont(QStringLiteral("楷体"),fontSize));
        textItem->setPen(*m_pPen);
        int width=textItem->boundingRect().width();
        int height=textItem->boundingRect().height();
        x=x-width/2;
        y=y-height/2;
        textItem->setPos(x,y);
    }
    
    void Canvas::setRange(float cormin, float cormax)
    {
        int cornumber=4;
        float corstep,tmpstep,tmpnumber,temp,extranumber;
        if(cormax<=cormin)
            return ;
        corstep=(cormax-cormin)/cornumber;
        if(pow(10,(int)(log(corstep)/log(10)))==corstep)
        {
            temp = pow(10,(int)(log(corstep)/log(10)));
        }
        else
        {
            temp = pow(10,((int)(log(corstep)/log(10))+1));
        }
        tmpstep = corstep/temp;
        //选取规范步长
        if(tmpstep>=0&&tmpstep<=0.1)
        {
            tmpstep = 0.1f;
        }
        else if(tmpstep>=0.100001&&tmpstep<=0.2)
        {
            tmpstep = 0.2f;
        }
        else if(tmpstep>=0.200001&&tmpstep<=0.25)
        {
            tmpstep = 0.25f;
        }
        else if(tmpstep>=0.250001&&tmpstep<=0.5)
        {
            tmpstep = 0.5f;
        }
        else
        {
            tmpstep = 1;
        }
        tmpstep = tmpstep * temp;
        //判断最小刻度是否需要+1
        if((int)(cormin/tmpstep)!=(cormin/tmpstep))
        {
            if(cormin<0)
            {
                cormin = (-1) * ceil(abs(cormin/tmpstep))*tmpstep;
            }
            else
            {
                cormin = (int)(abs(cormin/tmpstep))*tmpstep;
            }
    
        }
        if((int)(cormax/tmpstep)!=(cormax/tmpstep))
        {
            cormax = (int)(cormax/tmpstep+1)*tmpstep;
        }
        tmpnumber = (cormax-cormin)/tmpstep;
        if(tmpnumber<cornumber)
        {
            extranumber = cornumber - tmpnumber;
            tmpnumber = cornumber;
            if((int)extranumber%2 == 0)
            {
                cormax = cormax + tmpstep*(int)(extranumber/2);
            }
            else
            {
                cormax = cormax + tmpstep*(int)(extranumber/2+1);
            }
            cormin = cormin - tmpstep*(int)(extranumber/2);
        }
        cornumber = tmpnumber;
        m_cormax=cormax;
        m_cormin=cormin;
        m_cornumber=cornumber;
    }
    
    void Canvas::curvePlotting()
    {
        addAllRgb(m_data.size());
        if(m_data.size()==0)return;
        int offset=-10;
        int lastX=0,lastY=0;
        for(int i=0;i<m_data.size();i++)
        {
            m_pPen->setWidth(2);
            m_pPen->setColor(QColor(m_rgbs.at(i).r,m_rgbs.at(i).g,m_rgbs.at(i).b));
            QGraphicsLineItem *lineItem = m_pScene->addLine(QLineF(m_bottomPointX+20,-m_halfHeight+30+offset,m_bottomPointX+60,-m_halfHeight+30+offset));
            lineItem->setPen(*m_pPen);
            //正方形
            QGraphicsRectItem *m_rectItem=m_pScene->addRect(QRectF(m_bottomPointX+35,-m_halfHeight+30+offset-5,10,10));
            m_rectItem->setPen(*m_pPen);
            setText(m_bottomPointX+100,-m_halfHeight+30+offset,m_data.at(i).legend,15);
            offset+=20;
            bool isFirst=true;
            foreach (QPointF point, m_data[i].points)
            {
    
                float dataX;float angle;
                dataX=point.x();
                angle=point.y();
                float ratioOffset = m_interval/(m_scaleWidth*5);
                dataX=dataX-m_cormin;
                int currtX = dataX/ratioOffset;
                int x=(int)abs(currtX)*cosf(-(angle)*m_pi/180);
                int y=(int)abs(currtX)*sinf(-(angle)*m_pi/180);
                if(m_data[i].points.size()!=1&&!isFirst)
                {
                    m_pPen->setWidth(2);
                    m_pPen->setColor(QColor(m_rgbs.at(i).r,m_rgbs.at(i).g,m_rgbs.at(i).b));
                    QGraphicsLineItem *lineItem = m_pScene->addLine(QLineF(lastX,lastY,x,y));
                    lineItem->setPen(*m_pPen);
                }
                isFirst=false;
                lastX=x;
                lastY=y;
                x=x-m_scaleWidth/2;
                y=y-m_scaleWidth/2;
                //正方形
                QGraphicsRectItem *rect=m_pScene->addRect(QRectF(x,y,m_scaleWidth,m_scaleWidth));
                m_pPen->setWidth(2);
                m_pPen->setColor(QColor(m_rgbs.at(i).r,m_rgbs.at(i).g,m_rgbs.at(i).b));
                rect->setPen(*m_pPen);
            }
        }
    }
    
    void Canvas::addAllRgb(int rgbCount)
    {
        if(m_rgbs.size()>0)return;
        for (int i = 0; i < rgbCount; ++i)
        {
            int rgb[3];
            creatRgb(rgb);
            Rgb newRgb;
            newRgb.r=rgb[0];
            newRgb.g=rgb[1];
            newRgb.b=rgb[2];
            m_rgbs.append(newRgb);
        }
    }
    
    void Canvas::creatRgb(int *rgb)
    {
        for(int i=0;i<=200;i++)
        {
            for (int j = 0; j < 3; ++j)
            {
                QTime time;
                time= QTime::currentTime();
                qsrand(time.msec()*qrand()*qrand());
                int randNum = qrand() % 240;
                if(j==0)rgb[0]=randNum;
                if(j==1)rgb[1]=randNum;
                if(j==2)rgb[2]=randNum;
            }
            if(rgb[0]>200&&rgb[1]>200&&rgb[2]>200)continue;
            if(rgb[0]<40&&rgb[1]<40&&rgb[2]<40)continue;
            if(m_rgbs.size()==0)return;
            for (int k = 0; k < m_rgbs.size(); ++k)
            {
                if(sqrt(pow(m_rgbs.at(k).r-rgb[0],2)+pow(m_rgbs.at(k).g-rgb[1],2)+pow(m_rgbs.at(k).b-rgb[2],2))<80)
                {
                    break;
                }
                if(k==m_rgbs.size()-1)return;
            }
        }
    }
    
    void Canvas::setTitle(const QString& title)
    {
        m_title = title;
    }
    
    void Canvas::setStepAngle(double angle)
    {
        m_stepAngle=angle;
    }
    
    void Canvas::clearLine()
    {
       m_data.clear();
       resetAttribute();
       draw();
    }
    
    void Canvas::addLine(const QString& legend, const QString& xLeble, const QString& yLeble, const QVector<QPointF>& points)
    {
        Data data;
        data.legend=legend;
        data.xLeble=xLeble;
        data.yLeble=yLeble;
        data.points=points;
        m_data.append(data);
    }
    
    void Canvas::resizeEvent(QResizeEvent* event)
    {
        resetAttribute();
        draw();
        event->ignore();
    }
    
    void Canvas::test()
    {
        setRange(100,200);
        setTitle(QStringLiteral("xxx曲线"));
        setStepAngle(180);
        //添加线
        for (int var = 0; var < 20; ++var)
        {
            QVector<QPointF>line;
            line.append(QPoint(125,0));
            line.append(QPoint(125,30));
            line.append(QPoint(110,20));
            addLine("R=60m","","",line);
        }
        //画画
        draw();
    }
    

    mainwindow.cpp

    #include "MainWindow.h"
    #include "ui_MainWindow.h"
    #include"Canvas.h"
    #include<QHBoxLayout>
    #include<QDebug>
    #include <QVector2D>
    #include <QPushButton>
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        m_pVBoxLayout=new QVBoxLayout();
        m_pCanv=new Canvas;
        ui->centralwidget->setLayout(m_pVBoxLayout);
        m_pVBoxLayout->setContentsMargins(0,0,0,0);
        m_pVBoxLayout->addWidget(m_pCanv);
        m_pCanv->test();
        m_pBotton =new QPushButton;
        m_pBotton->setText("clear");
        m_pVBoxLayout->addWidget(m_pBotton);
        connect(m_pBotton,&QPushButton::clicked,[this]{
         m_pCanv->clearLine();
        });
    }
    
    MainWindow::~MainWindow()
    {
        delete m_pVBoxLayout;
        delete m_pCanv;
        delete m_pBotton;
        delete ui;
    }
    
    image.png

    相关文章

      网友评论

        本文标题:QT 自定义绘制图形Item+QGraphicsView

        本文链接:https://www.haomeiwen.com/subject/rzrjwltx.html