Skip to content

QtCharts使用

Published: at 01:38 AM | 4 min read

QtCharts是Qt的图表模块在Qt5.7版本之后才包含进来的,之前的版本需要下载源码单独编译。

介绍几个重要的类:
QChart:Qt图标的核心类,建立在图形视图之上的,管理各个图表部件
QChartView:是一个独立的widget用来展示QChart
QDateTimeAxis:日期时间轴
QValueAxis:数值轴
QLineSeries:折线图
QScatterSeries:离散图

demo截图:
qcharts_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);
}