最近因项目需要绘制蛛网图,雷达图,于是就参考了https://blog.csdn.net/chyuanrufeng/article/details/76222533的文章,在此基础上做以修改,达到了自己想要的效果。在此感谢这位博主的分享,话不多说上代码。

实现的效果图:

基于QWidget绘制蛛网图


源码如下 

RadarChart.h

#ifndef RADARCHART_H
#define RADARCHART_H

#include <QWidget>
#include <QPainter>
#include <QPainterPath>
#include "qmath.h"

enum RadarType
{
    Radar,  //雷达图
    Spider    //蛛网图
};

enum PointTpye
{
    ScatterPoints, //散点图
    LinePoints       //连线图
};

struct RadarData
{
    RadarData(const QString& _name,const qreal &_value){ name = _name;value=_value;}
    QString name;
    qreal value;
};

#define  PI M_PI

class RadarChart : public QWidget
{
    Q_OBJECT
public:
    explicit RadarChart(QWidget *parent = 0);
    void setRadarType(RadarType radartype);
    void setPointTpye(PointTpye pointstype);
    void setRadialAxisLabelVisible(bool visible){ m_showRadialAxisLabel = visible;this->update();}
    void setAngularAxisLabelVisible(bool visible){ m_showAngularAxisLabel = visible;this->update();}
    void setTitle(const QString &title){ m_title = title;this->update(); }
    void setTitleFont(const QFont &titleFont){ m_titleFont = titleFont; this->update();}
    void setTitleColor(const QColor &titleColor){ m_titleColor = titleColor; this->update();}
    void setDatas(const QList<RadarData> &datas);
    void setTickCount(int tickCount){ m_tickCount = tickCount; this->update();}
    void setAxisRange(qreal min,qreal max);
    void setAngularLineColor(const QColor &color){ m_AngularLineColor = color;this->update();}
    void setRadialLineColor(const QColor &color){ m_RadialLineColor = color;this->update();}
    void setAngularLabelColor(const QColor &color){ m_AngularLabelColor = color;this->update();}
    void setRadialLabelColor(const QColor &color){ m_RadialLabelColor = color;this->update();}
    void setSeriesColor(const QColor &color){ m_seriesColor = color;this->update();
    void setbackgroundColor(const QColor &color){ m_backgroundColor = color;this->update();}
    void setLabelFont(const QFont &labelFont){ m_labelFont = labelFont; this->update();}
protected:
    void paintEvent(QPaintEvent *event);

private:
    void init();
    void drawTitle(QPainter *painter);
    void drawRadarType(QPainter *painter);
    void drawRadar(QPainter *painter);
    void drawSpider(QPainter *painter);
    void drawRadialLabel(QPainter *painter);
    void drawAngularLabel(QPainter *painter);
    void drawData(QPainter *painter);
    void drawScatterPoints(QPainter *painter);
    void drawLinePoints(QPainter *painter);

private:
    RadarType m_radartype;
    PointTpye m_pointstype;
    bool m_showRadialAxisLabel;
    bool m_showAngularAxisLabel;

    QString m_title;
    QFont m_titleFont;
    QColor m_titleColor;
    QList<RadarData> m_datas;
    int m_tickCount;
    int m_AngularCount;
    qreal m_Axis_min;
    qreal m_Axis_max;
    QColor m_AngularLineColor;
    QColor m_RadialLineColor;
    QColor m_AngularLabelColor;
    QColor m_RadialLabelColor;
    QColor m_seriesColor;

  QColor m_backgroundColor;
    
    QFont m_labelFont;

    qreal m_titleHeight;
};

#endif // RADARCHART_H

RadarChart.cpp

#include "RadarChart.h"

RadarChart::RadarChart(QWidget *parent) : QWidget(parent)
{
    init();
}

void RadarChart::setDatas(const QList<RadarData> &datas)
{
    m_datas = datas;
    m_AngularCount = m_datas.count();
    this->update();
}

void RadarChart::setRadarType( RadarType radartype )
{
    m_radartype = radartype;
    this->update();
}

void RadarChart::setPointTpye( PointTpye pointstype )
{
    m_pointstype = pointstype;
    this->update();
}

void RadarChart::setAxisRange(qreal min,qreal max)
{
    m_Axis_min = min;
    m_Axis_max = max;
    this->update();
}

void RadarChart::init()
{
    m_radartype = Spider;
    m_pointstype = LinePoints;
    m_showRadialAxisLabel = true;
    m_showAngularAxisLabel = true;
    m_AngularCount = 0;

    m_titleFont = QFont("Arial",12,QFont::Bold);
    m_titleColor = Qt::black;
    m_tickCount = 5;

    m_Axis_min = 0;
    m_Axis_max = 10;

    m_AngularLineColor = Qt::black;
    m_RadialLineColor = Qt::black;
    m_AngularLabelColor = Qt::black;
    m_RadialLabelColor = Qt::black;
    m_seriesColor = QColor(102,170,238);
    m_labelFont = QFont("Arial",9);
    m_backgroundColor = Qt::white;
}


void RadarChart::paintEvent( QPaintEvent *event )
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    painter.setRenderHint(QPainter::TextAntialiasing);
    //添加背景颜色
    painter.save();
    painter.setBrush(m_backgroundColor);
    painter.drawRect(0,0,width(),height());
    painter.restore();


    drawTitle(&painter);
    drawData(&painter);
    drawRadarType(&painter);
    drawRadialLabel(&painter);
    drawAngularLabel(&painter);

    QWidget::paintEvent(event);
}

void RadarChart::drawTitle(QPainter *painter)
{
    painter->save();

    QPen pen;
    pen.setColor(m_titleColor);
    painter->setPen(pen);
    painter->setFont(m_titleFont);
    qreal w = width();
    QFontMetricsF fontMetrics(m_titleFont);
    qreal strWidth = fontMetrics.width(m_title);
    qreal strHeight = fontMetrics.height();
    qreal cur_x,cur_y;
    cur_x = w / 2 - strWidth / 2;
    cur_y = 10 + strHeight;
    m_titleHeight = cur_y + 5;
    painter->drawText(cur_x,cur_y,m_title);

    painter->restore();
}

void RadarChart::drawRadarType( QPainter *painter )
{
    switch (m_radartype)
    {
        case Radar:drawRadar(painter);break;
        case Spider:drawSpider(painter);break;
        default:drawRadar(painter);break;
    }
}


void RadarChart::drawRadar( QPainter *painter )
{
    painter->save();
    QPen pen;
    pen.setWidthF(0.4);
    pen.setColor(m_AngularLineColor); 
    painter->setPen(pen);

    qreal w = width();
    qreal h = height() - m_titleHeight;

    //绘制环线
    qreal radius = qMin(w,h)/2; //半径
    qreal step = radius/(m_tickCount+1);  //每环之间的距离
    qreal x0 = w/2 ;    //中心点X坐标
    qreal y0 = h/2 + m_titleHeight;     //中心点Y坐标
    qreal cur_x,cur_y;

    QPainterPath loopPath;
    for (int i = 1; i < m_tickCount+1; ++i)
    {
        qreal curRadius = step*i;
        loopPath.addEllipse(QPointF(x0, y0), curRadius, curRadius);
    }
    painter->drawPath(loopPath);

    pen.setColor(m_RadialLineColor); 
    painter->setPen(pen);

    //绘制中心到边缘的直线
    qreal dRadian = PI*2 / m_AngularCount;  //每个环形标签之间的夹角
    for (int i = 0 ; i < m_AngularCount; ++i)
    {
        cur_x = x0 + radius*qSin(dRadian*i);
        cur_y = y0 - radius*qCos(dRadian*i);

        painter->drawLine(x0,y0,cur_x,cur_y);
    }

    painter->restore();
}

void RadarChart::drawSpider( QPainter *painter )
{
    painter->save();
    QPen pen;
    pen.setWidthF(0.4);
    pen.setColor(m_AngularLineColor);
    painter->setPen(pen);

    qreal w = width();
    qreal h = height() - m_titleHeight;
    qreal radius = qMin(w,h)/2;
    qreal step = radius/(m_tickCount+1);
    qreal dRadian = PI*2 / m_AngularCount;
    qreal x0 = w/2 ;    
    qreal y0 = h/2 + m_titleHeight;     
    qreal cur_x,cur_y;

    QPointF *points = new QPointF[m_AngularCount + 1];
    for (int j = 1 ; j < m_tickCount + 1; ++j)
    {
        qreal curRadius = step*j;
        for (int i = 0 ; i < m_AngularCount; ++i)
        {
            cur_x = x0 + curRadius*qSin(dRadian*i);
            cur_y = y0 - curRadius*qCos(dRadian*i);
            points[i] = QPointF(cur_x,cur_y);
        }
        points[m_AngularCount] = points[0];
        painter->drawPolyline(points,m_AngularCount + 1);
    }

    pen.setColor(m_RadialLineColor);
    painter->setPen(pen);

    for (int i = 0 ; i < m_AngularCount; ++i)
    {
        painter->drawLine(x0,y0,points[i].x(),points[i].y());
    }

    delete []points;
    painter->restore();
}

void RadarChart::drawRadialLabel( QPainter *painter )
{
    if (!m_showRadialAxisLabel) return;
    painter->save();

    qreal w = width();
    qreal h = height() - m_titleHeight;
    qreal radius = qMin(w,h)/2;
    qreal step = radius/(m_tickCount+1);
    qreal x0 = w/2 ;    
    qreal y0 = h/2 + m_titleHeight;     
    qreal cur_x,cur_y;

    QPen pen;
    pen.setColor(m_RadialLabelColor);
    painter->setPen(pen);
    painter->setFont(m_labelFont);

    qreal dY = (m_Axis_max - m_Axis_min)/(m_tickCount);
    qreal offset = 20;
    if( step < 40 )
        offset = step / 2;

    for (int j = 0 ; j < m_tickCount+1; ++j)
    {
        qreal curRadius = step*j;
        cur_x = x0 + 2;
        cur_y = y0 - curRadius + offset;
        qreal value = m_Axis_min + dY * j;
        QString str = QString::number(value,'f',2);
        painter->drawText(cur_x,cur_y,str);
    }

    painter->restore();
}

void RadarChart::drawAngularLabel( QPainter *painter )
{
    if (!m_showAngularAxisLabel) return;

    painter->save();

    qreal w = width();
    qreal h = height() - m_titleHeight;
    qreal radius = qMin(w,h)/2;
    qreal x0 = w/2 ;    
    qreal y0 = h/2 + m_titleHeight;     
    qreal newRadius = m_tickCount * radius/(m_tickCount+1) + 5;
    qreal cur_x,cur_y;
    qreal dRadian = PI*2 / m_AngularCount;

    QPen pen;
    pen.setColor(m_RadialLabelColor);
    painter->setPen(pen);

    painter->setFont(m_labelFont);

    QFontMetricsF fontMetrics(m_labelFont);
    qreal strWidth,strHeight;

    qreal dError;
    for (int i = 0 ; i < m_AngularCount; ++i)
    {
        cur_x = x0 + newRadius*qSin(dRadian*i);
        cur_y = y0 - newRadius*qCos(dRadian*i);

        strWidth = fontMetrics.width(m_datas.at(i).name);
        strHeight = fontMetrics.height();
        dError = abs(cur_x - x0);
        if( dError < 1e-8 )         //cur_x == x0
            cur_x -= strWidth / 2;
        else
        {
            if( cur_x < x0 )
                cur_x = cur_x - strWidth - 2;
            else if( cur_x > x0 )
                cur_x += 2;
        }

        dError = abs(cur_y - y0);
        if( dError < 1e-8 )         //cur_y == y0
            cur_y += strHeight / 2;
        else
        {
            if( cur_y > y0 )
                cur_y -= strHeight *qCos(dRadian*i) ;
            else if( cur_y < y0 )
                cur_y = cur_y - strHeight *qCos(dRadian*i) + strHeight;
        }

        painter->drawText(cur_x,cur_y,m_datas.at(i).name);
    }

    painter->restore();
}

void RadarChart::drawData( QPainter *painter )
{
    switch(m_pointstype)
    {
    case ScatterPoints:drawScatterPoints(painter);break;
    case LinePoints:drawLinePoints(painter);break;
    default:drawLinePoints(painter);break;
    }

}

void RadarChart::drawScatterPoints( QPainter *painter )
{
    painter->save();

    qreal w = width();
    qreal h = height() - m_titleHeight;
    qreal radius = qMin(w,h)/2;
    qreal x0 = w/2 ;    
    qreal y0 = h/2 + m_titleHeight;     
    radius = m_tickCount * radius/(m_tickCount+1);
    qreal cur_x,cur_y;
    qreal dRadian = PI*2 / m_AngularCount;
    qreal step = 1.0*radius/(m_Axis_max-m_Axis_min);

    painter->setPen(m_seriesColor.darker(200));
    painter->setBrush(m_seriesColor.darker(200));

    for( int i = 0; i < m_AngularCount ; i++ )
    {
        qreal valueLength = m_datas.at(i).value * step;

        cur_x = x0 + valueLength*qSin(dRadian*i);
        cur_y = y0 - valueLength*qCos(dRadian*i);

        painter->drawEllipse(QPointF(cur_x,cur_y),4,4);
    }

    painter->restore();
}

void RadarChart::drawLinePoints( QPainter *painter )
{
    painter->save();

    qreal w = width();
    qreal h = height() - m_titleHeight;
    qreal radius = qMin(w,h)/2;
    qreal x0 = w/2 ;    
    qreal y0 = h/2 + m_titleHeight;     
    radius = m_tickCount * radius/(m_tickCount+1);
    qreal cur_x,cur_y;
    qreal dRadian = PI*2 / m_AngularCount;
    qreal step = 1.0*radius/(m_Axis_max-m_Axis_min);

    painter->setPen(m_seriesColor.darker(200));
    painter->setBrush(m_seriesColor.darker(200));

    QPointF *points = new QPointF[m_AngularCount];
    for( int i = 0; i < m_AngularCount ; i++ )
    {
        qreal valueLength = m_datas.at(i).value * step;

        cur_x = x0 + valueLength*qSin(dRadian*i);
        cur_y = y0 - valueLength*qCos(dRadian*i);

        points[i] = QPointF(cur_x,cur_y);
        painter->drawEllipse(QPointF(cur_x,cur_y),2,2);
    }

    painter->setBrush(m_seriesColor.lighter(100));
    painter->drawPolygon(points,m_AngularCount);

    painter->restore();
}

当然调用也很简单:

#include "mainwindow.h"
#include "RadarChart.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    RadarChart * widget = new RadarChart(this);

    QList<RadarData> datas;
    datas<<RadarData("Jan",10)<<RadarData("Feb",30)<<RadarData("Mar",50)<<RadarData("Apr",90)<<RadarData("May",20);
    widget->setDatas(datas);
    widget->setAxisRange(0,100);

    this->setCentralWidget(widget);
    this->resize(600,600);
}


到这里就结束啦,希望能帮到大家~

相关文章:

  • 2022-02-24
  • 2021-09-11
  • 2021-08-13
  • 2021-06-28
  • 2022-12-23
  • 2022-12-23
  • 2021-05-25
猜你喜欢
  • 2021-06-29
  • 2021-11-14
  • 2022-12-23
  • 2021-11-28
  • 2022-01-10
  • 2022-12-23
  • 2021-10-01
相关资源
相似解决方案