前言
未经允许,禁止转载
项目源码: 传送门
1.介绍
Qt图标(Qt Charts)出现晚于QWT、QCustomPlot,界面看起来也很优美,最主要的是要比后两种实现起来方便许多,当然,在自主灵活性上面就差了一点。
QChart已经集成在Qt5.7中,使用时在项目文件中加QT += charts
即可,不过在安装Qt过程中,QChart默认时不勾选的,在安装时需要用户自行勾选。
2.效果
柱状图:可设置标题栏,X轴标题, Y轴标题,柱形颜色,轴刻度,是否显示提示信息(柱形颜色含义)等
饼状图:可设置空心圆、实心圆、点击扇形弹出(信息可编辑)、提示信息(扇形颜色含义)、空心大小比例,图形名称等
折线图:可多条线一起显示、X轴名称、刻度尺,Y轴名称、刻度尺,提示信息,图形名称,X轴为时间轴等
曲线图:可多条线一起显示、X轴名称、刻度尺,Y轴名称、刻度尺,提示信息,图形名称,X轴为时间轴等
一、实现(以下代码必要部分都已加注释)
1.集成后的CMyChart
由于我的负责的项目中,以上四种图形都需要使用,所以使用开闭将这四种集成了一下,如果只使用一种,那么这一部分可以过滤不看,只需要将项目中的文件单独拿出来即可。
调用顺序:GetChartWithType->SetAxisXRange/SetAxisYRange/SetDateTimeAxisX->SetAxisXTitle/SetAxisYTitle->AppendSeries
头文件
#ifndef CMYCHART_H
#define CMYCHART_H
#include <QObject>
#include <QtCharts>
QT_CHARTS_USE_NAMESPACE
struct BarDateInfo
{
QString qsKey;
QVector<qreal> vecVal;
};
class CMyChart : public QObject
{
Q_OBJECT
public:
enum EType
{
eInvalid, //无效
eBarChart, //柱状图
ePieChart, //饼状图
eLineChart, //折线图
eSplineChart //曲线图
};
enum EColor
{
eBlue, //蓝色
eGreen, //绿色
eYellow, //黄色
ePurple, //紫色
eRed, //红色
eLightBlue, //淡蓝色
eLightGreen, //淡绿色
eLightYellow, //淡黄色
eLightPurple, //淡紫色
};
public:
CMyChart(const CMyChart::EType& type, QChartView* pView, QObject *parent = nullptr);
virtual ~CMyChart();
public:
//根据选择的图形,返回CMyChart
static CMyChart* GetChartWithType(const EType& eType, QChartView* pView);
//根据传入颜色转换成QColor
QColor toQColor(const EColor& eColor);
public:
//清空界面上显示的图形
virtual void ClearGraphical() = 0;
//设置提示信息是否显示
void SetLegend(bool bLegend = true);
//设置标题栏
void SetTitle(const QString& qsTitle);
//设置X轴坐标、刻度尺,柱状图、饼状图调此接口无用
virtual void SetAxisXRange(const qreal& qMin = 0, const qreal& qMax = 10, const int& nTickCount = 5){
};
//设置Y轴坐标、刻度尺,柱状图、饼状图调此接口无用
virtual void SetAxisYRange(const qreal& qMin = 0, const qreal& qMax = 10, const int& nTickCount = 5){
};
//设置时间坐标轴,柱状图、饼状图调此接口无用
virtual void SetDateTimeAxisX(const QDateTime& dtStart,
const QDateTime& dtEnd,
const QString& qsFormat = "yyyy-MM-dd",
const int& nTickCount = 5){
};
//设置X轴标题,饼状图调此接口无用
virtual void SetAxisXTitle(const QString& qsAxisXTitle){
};
//设置Y轴标题,柱状图调此接口无用
virtual void SetAxisYTitle(const QString& qsAxisYTitle){
};
//柱状图添加一组数据
virtual void AppendSeries(const QString& qsAxisXName,
QMap<QString, qreal>& mapData,
const QVector<EColor>& vecColors = m_vecDefCol){
};
//饼状图添加数据
virtual void AppendSeries(QMap<QString, qreal>& mapData, const QVector<EColor>& vecColors = m_vecDefCol){
};
//折线图、曲线图添加一条线
virtual void AppendSeries(const QString& name, QMap<qreal, qreal> mapVal){
};
//折线图、曲线图添加坐标轴为时间的一条线
virtual void AppendSeries(const QString& name, QMap<QDateTime, qreal> mapVal){
};
public:
EType m_eType;
QChart* m_pChart;
QChartView* m_pChartView;
static QVector<EColor> m_vecDefCol; //默认颜色顺序
};
#endif // CMYCHART_H
源文件:
#include "CMyChart.h"
#include "CMyBarChart.h"
#include "CMyPieChart.h"
#include "CMyLineChart.h"
#include "CMySplineChart.h"
QVector<CMyChart::EColor> CMyChart::m_vecDefCol = {
eBlue, eGreen, eYellow, ePurple, eRed, eLightBlue, eLightGreen, eLightYellow, eLightPurple};
CMyChart::CMyChart(const CMyChart::EType& type, QChartView* pView, QObject *parent)
: QObject (parent), m_eType(type), m_pChartView(pView)
{
m_pChart = new QChart;
m_pChart->setAnimationOptions(QChart::SeriesAnimations);
m_pChart->legend()->setVisible(true); //设置提示打开(默认打开)
m_pChart->legend()->show(); //显示提示
m_pChart->layout()->setContentsMargins(0, 0, 0, 0); //设置布局边距
m_pChart->setMargins(QMargins(0, 0, 0, 0)); //设置控件边距
m_pChart->setBackgroundRoundness(0); //保存图表背景角上的圆角的直径。
m_pChartView->setChart(m_pChart);
m_pChartView->setRenderHint(QPainter::Antialiasing); //防图形走样
}
CMyChart::~CMyChart()
{
}
CMyChart* CMyChart::GetChartWithType(const EType &eType, QChartView *pView)
{
if(pView == NULL)
return NULL;
switch (eType)
{
case eInvalid:
return NULL;
case eBarChart:
return new CMyBarChart(eType, pView);
case ePieChart:
return new CMyPieChart(eType, pView);
case eLineChart:
return new CMyLineChart(eType, pView);
case eSplineChart:
return new CMySplineChart(eType, pView);
default:
return NULL;
}
}
QColor CMyChart::toQColor(const EColor &eColor)
{
switch (eColor)
{
case eBlue:
return QColor(0, 122, 255);
case eGreen:
return QColor(27, 201, 133);
case eYellow:
return QColor(255,168, 0);
case ePurple:
return QColor(37, 217, 255);
case eRed:
return QColor(252, 79, 76);
case eLightBlue:
return QColor(104, 153, 255);
case eLightGreen:
return QColor(37, 217, 255);
case eLightYellow:
return QColor(255, 211, 35);
case eLightPurple:
return QColor(212, 139, 250);
default:
return QColor(0, 122, 255);
}
}
void CMyChart::SetLegend(bool bLegend)
{
if(bLegend)
m_pChart->legend()->show();
else
m_pChart->legend()->hide();
}
void CMyChart::SetTitle(const QString &qsTitle)
{
m_pChart->setTitle(qsTitle);
}
2.柱状图实现
头文件:
#ifndef CMYBARCHART_H
#define CMYBARCHART_H
#include <QObject>
#include "CMyChart.h"
class CMyBarChart : public CMyChart
{
Q_OBJECT
public:
explicit CMyBarChart(const CMyChart::EType& type, QChartView* pView, QObject *parent = nullptr);
virtual ~CMyBarChart();
public:
virtual void ClearGraphical();
virtual void SetAxisXTitle(const QString& qsAxisXTitle);
virtual void SetAxisYTitle(const QString& qsAxisYTitle);
virtual void SetAxisYRange(const qreal& qMin = 0, const qreal& qMax = 10, const int& nTickCount = 5);
virtual void AppendSeries(const QString& qsAxisXName,
QMap<QString, qreal>& mapData,
const QVector<EColor>& vecColors = m_vecDefCol);
private:
QValueAxis* m_pBarAxisY;
QBarSeries* m_pBarSeries;
QVector<QBarSet*> m_vecBarSet;
QBarCategoryAxis* m_pBarAxisX;
};
#endif // CMYBARCHART_H
源文件
#include "CMyBarChart.h"
CMyBarChart::CMyBarChart(const CMyChart::EType& type, QChartView* pView, QObject *parent)
: CMyChart(type, pView, parent)
{
m_pBarSeries = new QBarSeries; //创建分组系列
m_pBarSeries->setLabelsVisible(true); //设置显示柱形图值
m_pBarSeries->setLabelsPosition(QAbstractBarSeries::LabelsInsideEnd); //设置值位置
m_pChart->addSeries(m_pBarSeries); //将分组放入chart容器
m_pChart->createDefaultAxes(); //创建默认坐标轴
m_pChart->legend()->setAlignment(Qt::AlignBottom); //设置提示说明位置
m_vecBarSet.fill(NULL, 10); //默认最多只能有10个柱子
}
CMyBarChart::~CMyBarChart()
{
delete m_pBarSeries;
delete m_pBarAxisX;
delete m_pBarAxisY;
}
void CMyBarChart::ClearGraphical()
{
for(QVector<QBarSet*>::iterator it = m_vecBarSet.begin(); it != m_vecBarSet.end(); it++)
{
if(*it != NULL)
delete *it;
}
m_vecBarSet.fill(NULL, 10); //默认最多只有10种类型的柱子
m_pBarAxisX->clear();
m_pBarSeries->clear();
}
void CMyBarChart::SetAxisXTitle(const QString &qsAxisXTitle)
{
m_pBarAxisX->setTitleText(qsAxisXTitle);
}
void CMyBarChart::SetAxisYTitle(const QString &qsAxisYTitle)
{
m_pBarAxisY->setTitleText(qsAxisYTitle);
}
void CMyBarChart::SetAxisYRange(const qreal& qMin, const qreal& qMax, const int& nTickCount)
{
m_pBarAxisX = new QBarCategoryAxis; //创建X轴
m_pBarAxisY = new QValueAxis; //创建Y轴
m_pBarAxisX->setLabelsAngle(-45); //设置X轴坐标倾斜
m_pBarAxisY->setGridLineVisible(false); //设置网格不可见
m_pBarAxisY->setRange(qMin, qMax);
m_pBarAxisY->setTickCount(nTickCount);
m_pChart->setAxisX(m_pBarAxisX, m_pBarSeries); //将X坐标轴和分组进行统一
m_pChart->setAxisY(m_pBarAxisY, m_pBarSeries); //将Y坐标轴和分组进行统一
}
/*
* 一个QBarSet代表的是同一颜色的柱形,里面存放多个柱子的值
* 此接口先将一组数据作为柱子类型数的最大大小,然后根据先后顺序给柱子添加数据
*/
void CMyBarChart::AppendSeries(const QString &qsAxisXName, QMap<QString, qreal>& mapData, const QVector<EColor> &vecColors)
{
QMap<QString, qreal>::iterator it = mapData.begin();
for(int i = 0; i < mapData.size(); i++)
{
if(m_vecBarSet[i] == NULL)
{
m_vecBarSet[i] = new QBarSet(it.key());
m_vecBarSet[i]->setColor(toQColor(vecColors[i]));
}
m_vecBarSet[i]->append(it.value());
m_pBarSeries->append(m_vecBarSet[i]);
it++;
}
m_pBarAxisX->append(qsAxisXName);
}
3.饼状图实现
头文件
#ifndef CMYPIECHART_H
#define CMYPIECHART_H
#include <QObject>
#include "CMyChart.h"
class CMyPieChart : public CMyChart
{
Q_OBJECT
public:
explicit CMyPieChart(const CMyChart::EType& type, QChartView* pView, QObject *parent = nullptr);
virtual ~CMyPieChart();
public:
virtual void ClearGraphical();
virtual void AppendSeries(QMap<QString, qreal>& mapData, const QVector<EColor>& vecColors = m_vecDefCol);
private slots:
//点击扇形槽函数
void ClickedSector(QPieSlice* pSlice);
private:
QPieSeries* m_pPieSeries;
};
#endif // CMYPIECHART_H
源文件
#include "CMyPieChart.h"
CMyPieChart::CMyPieChart(const CMyChart::EType& type, QChartView* pView, QObject *parent)
: CMyChart(type, pView, parent)
{
m_pPieSeries = new QPieSeries;
m_pPieSeries->setHoleSize(0.5); //设置空心占比
m_pPieSeries->setPieSize(0.8); //设置圆形占比
m_pChart->addSeries(m_pPieSeries); //将饼图放入容器
m_pChart->legend()->setAlignment(Qt::AlignRight); //设置提示说明位置
connect(m_pPieSeries, SIGNAL(clicked(QPieSlice*)), this, SLOT(ClickedSector(QPieSlice*))); //点击扇形
}
CMyPieChart::~CMyPieChart()
{
delete m_pPieSeries;
}
void CMyPieChart::ClearGraphical()
{
m_pPieSeries->clear();
}
void CMyPieChart::ClickedSector(QPieSlice* pSlice)
{
if(pSlice->isExploded()) //判断扇形有没有弹出
{
pSlice->setExploded(false);
pSlice->setLabelVisible(false);
}
else {
pSlice->setExploded(true); //设置扇形弹出
pSlice->setLabelVisible(true); //设置扇形提示
}
}
void CMyPieChart::AppendSeries(QMap<QString, qreal> &mapData, const QVector<EColor> &vecColors)
{
m_pPieSeries->clear();
QMap<QString, qreal>::iterator it = mapData.begin();
for(int i = 0; i < mapData.size(); i++)
{
QPieSlice* pSlice = new QPieSlice(it.key(), it.value());
pSlice->setLabel(it.key());
pSlice->setColor(toQColor(vecColors[i]));
m_pPieSeries->append(pSlice);
it++;
}
}
4.折线图实现
头文件
#ifndef CMYLINECHART_H
#define CMYLINECHART_H
#include <QObject>
#include "CMyChart.h"
class CMyLineChart : public CMyChart
{
Q_OBJECT
public:
explicit CMyLineChart(const CMyChart::EType& type, QChartView* pView, QObject *parent = nullptr);
~CMyLineChart();
public:
virtual void ClearGraphical();
virtual void SetAxisXRange(const qreal& qMin = 0, const qreal& qMax = 10, const int& nTickCount = 5);
virtual void SetAxisYRange(const qreal& qMin = 0, const qreal& qMax = 10, const int& nTickCount = 5);
virtual void SetAxisXTitle(const QString& qsAxisXTitle);
virtual void SetAxisYTitle(const QString& qsAxisYTitle);
virtual void SetDateTimeAxisX(const QDateTime& dtStart,
const QDateTime& dtEnd,
const QString& qsFormat = "yyyy-MM-dd",
const int& nTickCount = 5);
virtual void AppendSeries(const QString& name, QMap<qreal, qreal> mapVal);
virtual void AppendSeries(const QString& name, QMap<QDateTime, qreal> mapVal);
private:
bool m_bIsDateTime;
QValueAxis* m_pLineAxisX;
QValueAxis* m_pLineAxisY;
QDateTimeAxis* m_pAxisDateTime;
QVector<QLineSeries*> m_vecLineSeries;
};
#endif // CMYLINECHART_H
源文件
#include "CMyLineChart.h"
CMyLineChart::CMyLineChart(const CMyChart::EType& type, QChartView* pView, QObject *parent)
: CMyChart(type, pView, parent)
{
m_bIsDateTime = false;
}
CMyLineChart::~CMyLineChart()
{
for(QVector<QLineSeries*>::iterator it = m_vecLineSeries.begin(); it != m_vecLineSeries.end(); it++)
delete *it;
}
void CMyLineChart::ClearGraphical()
{
for(QVector<QLineSeries*>::iterator it = m_vecLineSeries.begin(); it != m_vecLineSeries.end(); it++)
delete *it;
m_vecLineSeries.clear();
}
void CMyLineChart::SetAxisXRange(const qreal &qMin, const qreal &qMax, const int &nTickCount)
{
m_pLineAxisX = new QValueAxis;
m_pLineAxisX->setRange(qMin, qMax);
m_pLineAxisX->setTickCount(nTickCount);
m_pChart->addAxis(m_pLineAxisX, Qt::AlignBottom);
}
void CMyLineChart::SetAxisYRange(const qreal &qMin, const qreal &qMax, const int &nTickCount)
{
m_pLineAxisY = new QValueAxis;
m_pLineAxisY->setRange(qMin, qMax);
m_pLineAxisY->setTickCount(nTickCount);
m_pLineAxisY->setGridLineVisible(false);
m_pChart->addAxis(m_pLineAxisY, Qt::AlignLeft);
}
void CMyLineChart::SetDateTimeAxisX(const QDateTime &dtStart, const QDateTime &dtEnd, const QString &qsFormat, const int &nTickCount)
{
m_bIsDateTime = true;
m_pAxisDateTime = new QDateTimeAxis;
m_pAxisDateTime->setFormat(qsFormat);
m_pAxisDateTime->setRange(dtStart, dtEnd);
m_pAxisDateTime->setTickCount(nTickCount);
m_pChart->addAxis(m_pAxisDateTime, Qt::AlignBottom);
}
void CMyLineChart::SetAxisXTitle(const QString &qsAxisXTitle)
{
if(m_bIsDateTime)
m_pAxisDateTime->setTitleText(qsAxisXTitle);
else
m_pLineAxisX->setTitleText(qsAxisXTitle);
}
void CMyLineChart::SetAxisYTitle(const QString &qsAxisYTitle)
{
m_pLineAxisY->setTitleText(qsAxisYTitle);
}
void CMyLineChart::AppendSeries(const QString &name , QMap<qreal, qreal> mapVal)
{
QLineSeries* pLineSeries = new QLineSeries;
pLineSeries->setName(name);
pLineSeries->setPointsVisible(true);
pLineSeries->setPointLabelsVisible(true); //设置显示点位
m_pChart->addSeries(pLineSeries);
for(QMap<qreal, qreal>::iterator it = mapVal.begin(); it != mapVal.end(); it++)
pLineSeries->append(it.key(), it.value());
m_vecLineSeries.push_back(pLineSeries);
pLineSeries->attachAxis(m_pLineAxisX);
pLineSeries->attachAxis(m_pLineAxisY);
}
void CMyLineChart::AppendSeries(const QString &name, QMap<QDateTime, qreal> mapVal)
{
QLineSeries* pLineSeries = new QLineSeries;
pLineSeries->setName(name);
pLineSeries->setPointsVisible(true);
pLineSeries->setPointLabelsVisible(false); //设置显示点位
m_pChart->addSeries(pLineSeries);
for(QMap<QDateTime, qreal>::iterator it = mapVal.begin(); it != mapVal.end(); it++)
pLineSeries->append(it.key().toMSecsSinceEpoch(), it.value());
m_vecLineSeries.push_back(pLineSeries);
pLineSeries->attachAxis(m_pAxisDateTime);
pLineSeries->attachAxis(m_pLineAxisY);
}
5.曲线图实现
头文件
#ifndef CMYSPLINECHART_H
#define CMYSPLINECHART_H
#include <QObject>
#include "CMyChart.h"
class CMySplineChart : public CMyChart
{
Q_OBJECT
public:
explicit CMySplineChart(const CMyChart::EType& type, QChartView* pView, QObject *parent = nullptr);
~CMySplineChart();
public:
virtual void ClearGraphical();
virtual void SetAxisXRange(const qreal& qMin = 0, const qreal& qMax = 10, const int& nTickCount = 5);
virtual void SetAxisYRange(const qreal& qMin = 0, const qreal& qMax = 10, const int& nTickCount = 5);
virtual void SetAxisXTitle(const QString& qsAxisXTitle);
virtual void SetAxisYTitle(const QString& qsAxisYTitle);
virtual void SetDateTimeAxisX(const QDateTime& dtStart,
const QDateTime& dtEnd,
const QString& qsFormat = "yyyy-MM-dd",
const int& nTickCount = 5);
virtual void AppendSeries(const QString& name, QMap<qreal, qreal> mapVal);
virtual void AppendSeries(const QString& name, QMap<QDateTime, qreal> mapVal);
signals:
public slots:
private:
bool m_bIsDateTime;
QValueAxis* m_pLineAxisX;
QValueAxis* m_pLineAxisY;
QDateTimeAxis* m_pAxisDateTime;
QVector<QSplineSeries*> m_vecSplineSeries;
};
#endif // CMYSPLINECHART_H
源文件
#include "CMySplineChart.h"
CMySplineChart::CMySplineChart(const CMyChart::EType& type, QChartView* pView, QObject *parent)
: CMyChart(type, pView, parent)
{
m_bIsDateTime = false;
}
CMySplineChart::~CMySplineChart()
{
for(QVector<QSplineSeries*>::iterator it = m_vecSplineSeries.begin(); it != m_vecSplineSeries.end(); it++)
delete *it;
}
void CMySplineChart::ClearGraphical()
{
for(QVector<QSplineSeries*>::iterator it = m_vecSplineSeries.begin(); it != m_vecSplineSeries.end(); it++)
delete *it;
m_vecSplineSeries.clear();
}
void CMySplineChart::SetAxisXRange(const qreal &qMin, const qreal &qMax, const int &nTickCount)
{
m_pLineAxisX = new QValueAxis;
m_pLineAxisX->setRange(qMin, qMax);
m_pLineAxisX->setTickCount(nTickCount);
m_pChart->addAxis(m_pLineAxisX, Qt::AlignBottom);
}
void CMySplineChart::SetAxisYRange(const qreal &qMin, const qreal &qMax, const int &nTickCount)
{
m_pLineAxisY = new QValueAxis;
m_pLineAxisY->setRange(qMin, qMax);
m_pLineAxisY->setTickCount(nTickCount);
m_pLineAxisY->setGridLineVisible(false);
m_pChart->addAxis(m_pLineAxisY, Qt::AlignLeft);
}
void CMySplineChart::SetDateTimeAxisX(const QDateTime &dtStart, const QDateTime &dtEnd, const QString &qsFormat, const int &nTickCount)
{
m_bIsDateTime = true;
m_pAxisDateTime = new QDateTimeAxis;
m_pAxisDateTime->setFormat(qsFormat);
m_pAxisDateTime->setRange(dtStart, dtEnd);
m_pAxisDateTime->setTickCount(nTickCount);
m_pChart->addAxis(m_pAxisDateTime, Qt::AlignBottom);
}
void CMySplineChart::SetAxisXTitle(const QString &qsAxisXTitle)
{
if(m_bIsDateTime)
m_pAxisDateTime->setTitleText(qsAxisXTitle);
else
m_pLineAxisX->setTitleText(qsAxisXTitle);
}
void CMySplineChart::SetAxisYTitle(const QString &qsAxisYTitle)
{
m_pLineAxisY->setTitleText(qsAxisYTitle);
}
void CMySplineChart::AppendSeries(const QString &name , QMap<qreal, qreal> mapVal)
{
QSplineSeries* pSplineSeries = new QSplineSeries;
pSplineSeries->setName(name);
pSplineSeries->setPointsVisible(true);
pSplineSeries->setPointLabelsVisible(true); //设置显示点位
m_pChart->addSeries(pSplineSeries);
for(QMap<qreal, qreal>::iterator it = mapVal.begin(); it != mapVal.end(); it++)
pSplineSeries->append(it.key(), it.value());
m_vecSplineSeries.push_back(pSplineSeries);
pSplineSeries->attachAxis(m_pLineAxisX);
pSplineSeries->attachAxis(m_pLineAxisY);
}
void CMySplineChart::AppendSeries(const QString &name, QMap<QDateTime, qreal> mapVal)
{
QSplineSeries* pSplineSeries = new QSplineSeries;
pSplineSeries->setName(name);
pSplineSeries->setPointsVisible(true);
pSplineSeries->setPointLabelsVisible(false); //设置显示点位
m_pChart->addSeries(pSplineSeries);
for(QMap<QDateTime, qreal>::iterator it = mapVal.begin(); it != mapVal.end(); it++)
pSplineSeries->append(it.key().toMSecsSinceEpoch(), it.value());
m_vecSplineSeries.push_back(pSplineSeries);
pSplineSeries->attachAxis(m_pAxisDateTime);
pSplineSeries->attachAxis(m_pLineAxisY);
}
二、使用
使用QChart需要对于widget进行提升
项目源码:传送门
码字不易,各位观众老爷,如果觉得有点用,还请点个赞,让我涨涨积分哈!