my-QT专栏

QT 自定义绘制图形Item+QGraphicsView

2021-09-05  本文已影响0人  c之气三段

.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
上一篇 下一篇

猜你喜欢

热点阅读