QT通过paintEvent()绘制带渲染颜色的折线图

实现效果

源码

CLineChart.h

#ifndef CLINECHART_H
#define CLINECHART_H

#include <QWidget>
#include <QMouseEvent>

class CLineChart : public QWidget
{
    Q_OBJECT

public:
    CLineChart(QWidget *parent = 0);
    ~CLineChart();
    void initData();

protected:
    void mouseMoveEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *);
    // 绘制背景
    void drawBg(QPainter *painter);
    // 绘制边框
    void drawFrame(QPainter *painter);
    // 绘制中间线
    void drawMidline(QPainter *painter);
    // 绘制文字
    void drawText(QPainter *painter);
    // 绘制渐变颜色
    void drawGradualColor(QPainter *painter, QColor gradualColor, QVector<QPointF> listPoints);
    // 绘制数据线
    void drawDataLine(QPainter *painter, QColor lineColor, QVector<QPointF> listPoints);
    // 绘制鼠标在折线图中的竖线
    void drawMouseLine(QPainter *painter);

private:
    QRectF pointRect;       // 绘制数据区域
    QPointF m_mousePos;     // 鼠标在折线图中的坐标

    QVector<QPointF> m_vecHeightPoints;     // 高值数据点集合
    QVector<QPointF> m_vecLowPoints;        // 低值数据点集合

    QVector<QString> m_vecVerticalText;     // 垂直文本集合

    const double m_dMinValueY;      // y轴最小值
    const double m_dMaxValueY;      // y轴最大值
    const double m_dMinValueX;      // x轴最小值
    const double m_dMaxValueX;      // x轴最大值

    const double m_dStepX;      // x轴间隔数
    const double m_dStepY;      // y轴间隔数
    double m_dIncrementX;       // x轴间距
    double m_dIncrementY;       // y轴间距

    QColor m_colorBg;           // 背景颜色
    QColor m_colorBgFrame;      // 边框颜色
    QColor m_colorBgMidline;    // 中间线颜色
    QColor m_colorText;         // 文字颜色
    QColor m_colorBlueLine;     // 蓝色线颜色
    QColor m_colorYellowLine;   // 黄色线颜色
    QColor m_colorLineGradual;  // 线渐变颜色
    QColor m_colorPoint;        // 坐标点颜色
};

#endif // CLINECHART_H

CLineChart.cpp

#include "CLineChart.h"

#include <QPainter>
#include <QDebug>

CLineChart::CLineChart(QWidget *parent)
    : QWidget(parent)
    , m_dMinValueY(0)
    , m_dMaxValueY(384)
    , m_dMinValueX(19)
    , m_dMaxValueX(1251)
    , m_dStepX(30)
    , m_dStepY(6)
{
    this->setFixedSize(1296, 448);

    m_dIncrementX = (m_dMaxValueX - m_dMinValueX) / m_dStepX;       // 折线图水平方向间隔
    m_dIncrementY = (m_dMaxValueY - m_dMinValueY) / m_dStepY;       // 折线图竖直方向间隔

    m_colorBg.setNamedColor("#ffffff");
    m_colorBgFrame.setNamedColor("#f61b1b");
    m_colorBgMidline.setNamedColor("#d9d9d9");
    m_colorText.setNamedColor("#666666");
    m_colorBlueLine.setNamedColor("#2582ff");
    m_colorYellowLine.setNamedColor("#ffa225");
    m_colorLineGradual.setNamedColor("#2582ff");
    m_colorPoint.setNamedColor("d8d8d8");

    initData();
}

CLineChart::~CLineChart()
{

}

void CLineChart::initData()
{
    m_mousePos = QPointF(-100, -100);

    // 添加高值数据点集合
    m_vecHeightPoints.clear();
    m_vecHeightPoints.push_back(QPointF(158, 340));
    m_vecHeightPoints.push_back(QPointF(332, 255));
    m_vecHeightPoints.push_back(QPointF(476, 150));
    m_vecHeightPoints.push_back(QPointF(620, 230));
    m_vecHeightPoints.push_back(QPointF(764, 200));
    m_vecHeightPoints.push_back(QPointF(908, 350));
    m_vecHeightPoints.push_back(QPointF(1052, 220));
    m_vecHeightPoints.push_back(QPointF(1156, 180));

    // 添加低值数据点集合
    m_vecLowPoints.clear();
    m_vecLowPoints.push_back(QPointF(188, 360));
    m_vecLowPoints.push_back(QPointF(325, 240));
    m_vecLowPoints.push_back(QPointF(450, 300));
    m_vecLowPoints.push_back(QPointF(600, 280));
    m_vecLowPoints.push_back(QPointF(750, 365));
    m_vecLowPoints.push_back(QPointF(900, 250));
    m_vecLowPoints.push_back(QPointF(1100, 270));
    m_vecLowPoints.push_back(QPointF(1200, 220));

    // 添加竖直方向文字集合
    m_vecVerticalText.clear();
    m_vecVerticalText.push_back("3SD");
    m_vecVerticalText.push_back("2SD");
    m_vecVerticalText.push_back("1SD");
    m_vecVerticalText.push_back("X");
    m_vecVerticalText.push_back("-1SD");
    m_vecVerticalText.push_back("-2SD");
    m_vecVerticalText.push_back("-3SD");
}

void CLineChart::mouseMoveEvent(QMouseEvent *event)
{
    QPointF currentPos = event->pos();
    // 判断鼠标是否在折线图内
    if (pointRect.contains(currentPos.x(), currentPos.y()))
    {
        m_mousePos = event->pos();
    }
    this->update();
    QWidget::mouseMoveEvent(event);
}

void CLineChart::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

    // 设置折线图区域
    QPointF pointTopLeft(67, 15);       // 折线图左上角坐标
    QPointF pointBottomRight(width(), height() - 49);       // 折线图左下角坐标
    pointRect = QRectF(pointTopLeft, pointBottomRight);     // 折线图区域

    drawBg(&painter);       // 绘制背景
    drawFrame(&painter);    // 绘制上下边框
    drawMidline(&painter);  // 绘制中间线
    drawText(&painter);     // 绘制文字
    drawGradualColor(&painter, m_colorBlueLine, m_vecHeightPoints);     // 绘制蓝色渐变线
    drawGradualColor(&painter, m_colorYellowLine, m_vecLowPoints);      // 绘制黄色渐变线
    drawDataLine(&painter, m_colorBlueLine, m_vecHeightPoints);         // 绘制高值线
    drawDataLine(&painter, m_colorYellowLine, m_vecLowPoints);          // 绘制低值线
    drawMouseLine(&painter);        // 绘制鼠标竖线
}

void CLineChart::drawBg(QPainter *painter)
{
    if (NULL == painter)
    {
        return;
    }
    painter->save();
    painter->setPen(Qt::NoPen);
    QLinearGradient topGradient(rect().topLeft(), rect().bottomLeft());
    topGradient.setColorAt(0.0, m_colorBg);
    topGradient.setColorAt(1.0, m_colorBg);
    painter->setBrush(topGradient);
    painter->drawRect(rect());
    painter->restore();
}

void CLineChart::drawFrame(QPainter *painter)
{
    if (NULL == painter)
    {
        return;
    }
    painter->save();

    QPen penFrame;
    penFrame.setWidth(2);
    penFrame.setColor(m_colorBgFrame);

    painter->setPen(penFrame);
    painter->setBrush(Qt::NoBrush);

    QPointF pointTopLeft(pointRect.topLeft().x(), pointRect.topLeft().y());                 // 折线图左上角顶点
    QPointF pointTopRight(pointRect.topRight().x(), pointRect.topRight().y());              // 折线图右上角顶点
    QPointF pointBottomLeft(pointRect.bottomLeft().x(), pointRect.bottomRight().y());       // 折线图左下角顶点
    QPointF pointBottomRight(pointRect.bottomRight().x(), pointRect.bottomRight().y());     // 折线图右下角顶点
    painter->drawLine(pointTopLeft, pointTopRight);             // 连接左上角和右上角顶部实线
    painter->drawLine(pointBottomLeft, pointBottomRight);       // 连接左下角和右下角底部实线
    painter->restore();
}

void CLineChart::drawMidline(QPainter *painter)
{
    if (NULL == painter)
    {
        return;
    }
    painter->save();
    // 绘制横线
    QPen penMidline;
    penMidline.setWidth(1);
    penMidline.setColor(m_colorBgMidline);
    painter->setPen(penMidline);

    // 循环打印中间线
    double d_StartY = pointRect.topLeft().y();      // 中间线起始y坐标
    for (int iStep = 0; iStep < m_dStepY - 1; iStep++)
    {
        d_StartY += m_dIncrementY;
        QPointF pointLeft(pointRect.topLeft().x(), d_StartY);
        QPointF pointRight(pointRect.topRight().x(), d_StartY);
        painter->drawLine(pointLeft, pointRight);
    }
    painter->restore();
}

void CLineChart::drawText(QPainter *painter)
{
    if (NULL == painter)
    {
        return;
    }
    painter->save();

    painter->setPen(m_colorText);
    painter->setBrush(Qt::NoBrush);
    painter->setFont(QFont("SourceHanSansCH-Regular", 16, 1));

    double d_StartY = pointRect.topLeft().y();
    QString strValue;
    for (int iStepY = 0; iStepY <= m_dStepY; iStepY++)
    {
        strValue = QString("%1").arg(m_vecVerticalText[iStepY]);
        double d_TextWidth = fontMetrics().width(strValue);
        double d_TextHeight = fontMetrics().height();
        QPointF pointTextY(pointRect.topLeft().x() - 17 - d_TextWidth, d_StartY);
        painter->drawText(pointTextY, strValue);
        d_StartY += m_dIncrementY;
    }

    double d_StartX = pointRect.bottomLeft().x();
    for (int iStepX = 0; iStepX <= m_dStepX; iStepX++)
    {
        strValue = QString("%1").arg(iStepX);
        QPointF pointTextX(d_StartX + 19, pointRect.bottomLeft().y() + 27);
        painter->drawText(pointTextX, strValue);
        d_StartX += m_dIncrementX;
    }

    painter->restore();
}

void CLineChart::drawGradualColor(QPainter *painter, QColor gradualColor, QVector<QPointF> listPoints)
{
    if (NULL == painter)
    {
        return;
    }
    painter->save();

    // 将数据点集合添加 与水平轴相连的首尾节点
    QVector<QPointF> vec_TempListPoints = listPoints;
    double d_StartPointX = vec_TempListPoints[0].x();
    double d_EndPointX = vec_TempListPoints[vec_TempListPoints.size() - 1].x();
    vec_TempListPoints.prepend(QPointF(d_StartPointX, pointRect.bottomLeft().y() - 2));
    vec_TempListPoints.append(QPointF(d_EndPointX, pointRect.bottomRight().y() - 2));

    QColor transparent(Qt::red);
    transparent.setAlpha(0);
    QPen pen;
    pen.setWidth(2);
    pen.setColor(transparent);
    painter->setPen(pen);

    QLinearGradient linear(0, 0, 0, 384);
    QColor gradualBlueColor = gradualColor;
    gradualBlueColor.setAlphaF(0.3);
    linear.setColorAt(0.0, gradualBlueColor);
    linear.setColorAt(1.0, m_colorBg);
    linear.setSpread(QGradient::PadSpread);

    painter->setBrush(QBrush(linear));
    painter->drawPolygon(QPolygonF(vec_TempListPoints));
    qDebug() << "vec_TempListPoints:" << vec_TempListPoints;

    painter->restore();
}

void CLineChart::drawDataLine(QPainter *painter, QColor lineColor, QVector<QPointF> listPoints)
{
    if (NULL == painter)
    {
        return;
    }
    painter->save();

    QPen pen;
    pen.setWidth(2);
    pen.setColor(lineColor);
    painter->setPen(pen);

    // 循环打印数据点集合中的点
    for (int iStep = 0; iStep < listPoints.size() - 1; ++iStep)
    {
        painter->drawLine(listPoints[iStep], listPoints[iStep + 1]);
    }

    painter->restore();
}

void CLineChart::drawMouseLine(QPainter *painter)
{
    if (NULL == painter)
    {
        return;
    }
    painter->save();

    QPen penMouseline;
    penMouseline.setWidth(5);
    penMouseline.setColor(m_colorPoint);
    painter->setPen(penMouseline);
    // 绘制鼠标竖线
    painter->drawLine(m_mousePos.rx(), pointRect.topLeft().y() + 2, m_mousePos.rx(), pointRect.bottomLeft().y() - 2);

    painter->restore();
}

main.cpp

#include "CLineChart.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    CLineChart w;
    w.show();

    return a.exec();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值