实现效果
源码
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();
}