QtCharts是Qt的图表模块在Qt5.7版本之后才包含进来的,之前的版本需要下载源码单独编译。
介绍几个重要的类:
QChart:Qt图标的核心类,建立在图形视图之上的,管理各个图表部件
QChartView:是一个独立的widget用来展示QChart
QDateTimeAxis:日期时间轴
QValueAxis:数值轴
QLineSeries:折线图
QScatterSeries:离散图
demo截图:
源码:
MyChart.h
#pragma once
#include <QtCharts/QChart>
#include <QtCharts/QChartView>
#include <QPen>
using namespace QtCharts;
class QMouseEvent;
class QLabel;
class QTimer;
class QGraphicsLineItem;
class MyChart : public QChartView
{
Q_OBJECT
public:
MyChart(QWidget *parent = nullptr);
~MyChart();
void init();
void updateXList();
protected:
virtual void showEvent(QShowEvent *event);
virtual void mouseMoveEvent(QMouseEvent *event);
virtual void resizeEvent(QResizeEvent *event);
private:
QTimer *m_timer;
QLabel *m_showLabel;
QGraphicsLineItem *m_lineItem;
QList<QPointF> m_xList;
QPen m_middleLinePen;
QPoint m_middlePos;
};
MyChart.cpp
#include "MyChart.h"
#include <QEvent>
#include <QtCharts/QLineSeries>
#include <QtCharts/qxyseries.h>
#include <QtCore/QRandomGenerator>
#include <QtCharts/QBarCategoryAxis>
#include <QtCharts/QValueAxis>
#include <QtCharts/QDateTimeAxis>
#include <QtCharts/QScatterSeries>
#include <QTime>
#include <QTimer>
#include <QDateTime>
#include <QLabel>
#include <QDebug>
typedef QPair<qint64, int> Data;
typedef QList<Data> DataList;
typedef QList<DataList> DataTable;
const int g_listCount = 2;
DataTable g_dataTable;
int getRandom(int maxValue)
{
return QRandomGenerator::global()->bounded(maxValue);
}
DataTable generateRandomData(int listCount, int &maxX, int &maxY)
{
DataTable dataTable;
// generate random data
for (int i(0); i < listCount; i++) {
QDateTime start = QDateTime(QDateTime::currentDateTime().date(), QTime(8, 0));
DataList dataList;
int yValue(0);
int xIndex = 0;
for (int j(0); j < 11; j++) {
yValue = yValue + getRandom(100);
maxY = yValue;
maxX = xIndex++;
dataList << Data(start.toMSecsSinceEpoch(), yValue);
start = start.addSecs(3000);
}
dataTable << dataList;
}
return dataTable;
}
MyChart::MyChart(QWidget *parent)
: QChartView(parent), m_lineItem(nullptr)
{
init();
}
MyChart::~MyChart()
{
}
void MyChart::init()
{
m_middleLinePen.setStyle(Qt::DashLine);
m_middleLinePen.setColor(Qt::red);
m_timer = new QTimer(this);
m_timer->setSingleShot(true);
m_timer->setInterval(10);
m_showLabel = new QLabel(this);
m_showLabel->hide();
m_showLabel->setFixedSize(120, 60);
m_showLabel->setWindowFlag(Qt::ToolTip);
m_showLabel->setFocusPolicy(Qt::NoFocus);
int g_xMax = 0;
int g_yMax = 0;
g_dataTable = generateRandomData(g_listCount, g_xMax, g_yMax);
QDateTimeAxis *axisX = new QDateTimeAxis(); // X轴是时间
axisX->setFormat("HH:mm");
axisX->setTickCount(11);
QDateTime start = QDateTime(QDateTime::currentDateTime().date(), QTime(8, 0));
QDateTime end = QDateTime(QDateTime::currentDateTime().date(), QTime(18, 0));
axisX->setRange(start, end);
QValueAxis *axisY = new QValueAxis(); // Y轴是值
axisY->setRange(0, g_yMax * 1.5);
axisY->setLabelFormat("%i");
axisY->setTickCount(6);
QChart *chart = new QChart();
chart->setTitle("Line chart");
chart->addAxis(axisX, Qt::AlignBottom);
chart->addAxis(axisY, Qt::AlignLeft);
this->setChart(chart);
QString name("Series ");
int nameIndex = 0;
for (const DataList &list : g_dataTable) {
QLineSeries *lineSeries = new QLineSeries(); // 线图
QScatterSeries *scatterSeries = new QScatterSeries(); // 离散图
scatterSeries->setMarkerShape(QScatterSeries::MarkerShapeCircle);//圆形的点
scatterSeries->setBorderColor(QColor(21, 100, 255)); //离散点边框颜色
scatterSeries->setBrush(QBrush(QColor(21, 100, 255)));//离散点背景色
scatterSeries->setMarkerSize(6); //离散点大小
for (const Data &data : list) {
QPointF pp((qreal)data.first, (qreal)data.second);
lineSeries->append(pp);
scatterSeries->append(pp);
}
lineSeries->setName(name + QString::number(nameIndex));
nameIndex++;
chart->addSeries(lineSeries);
chart->addSeries(scatterSeries);
chart->legend()->hide(); // 图标标题
lineSeries->attachAxis(axisY);
lineSeries->attachAxis(axisX);
scatterSeries->attachAxis(axisY);
scatterSeries->attachAxis(axisX);
}
this->setRenderHint(QPainter::Antialiasing, true);
this->setMouseTracking(true);
}
void MyChart::updateXList()
{
m_xList.clear();
if (!g_dataTable.isEmpty()) {
for (int i = 0; i < g_dataTable[0].size(); i++) {
Data d = g_dataTable[0][i];
QPointF p = this->chart()->mapToPosition(QPointF(d.first, d.second));
m_xList << p;
}
}
}
void MyChart::showEvent(QShowEvent *event)
{
updateXList();
QChartView::showEvent(event);
}
void MyChart::resizeEvent(QResizeEvent *event)
{
updateXList();
QChartView::resizeEvent(event);
}
void MyChart::mouseMoveEvent(QMouseEvent *event)
{
QPoint p = event->pos();
if (this->chart()->plotArea().contains(p)) {
QPointF pf;
int lastDiff = -1;
foreach(const QPointF &px, m_xList) {
int diff = qAbs((int)px.x() - p.x());
if (lastDiff < 0) {
lastDiff = diff;
pf = px;
}
else {
if (diff < lastDiff) {
lastDiff = diff;
pf = px;
}
}
}
QPoint pf2((int)pf.x(), (int)pf.y());
if (m_middlePos != pf2) {
m_middlePos = pf2;
QPointF pv = this->chart()->mapToValue(pf);
QRectF r = this->chart()->plotArea();
QGraphicsLineItem *oldItem = m_lineItem;
m_lineItem = this->scene()->addLine(QLine(QPoint(m_middlePos.x(), (int)r.y()), QPoint(m_middlePos.x(), (int)(r.y() + r.height()))), m_middleLinePen);
if (oldItem) {
this->scene()->removeItem(oldItem);
}
QStringList ls;
ls << "xxx title";
ls << "time:" + QDateTime::fromMSecsSinceEpoch((qint64)pv.x()).toString("HH:mm");
ls << "deal:" + QString::number(pv.y());
m_showLabel->setText(ls.join("\n"));
}
QPoint labelPos = this->mapToGlobal(p);
labelPos.setX(labelPos.x() + 20);
labelPos.setY(labelPos.y() + 10);
m_showLabel->move(labelPos);
m_showLabel->show();
}
else {
m_showLabel->hide();
if (m_lineItem) {
this->scene()->removeItem(m_lineItem);
}
}
QChartView::mouseMoveEvent(event);
}