QtChart实现曲线图表绘制之直⾓坐标系(⽀持曲线消隐、数据点突出、数据驱
动刷新、⿏标进。。。
简述
Qt下绘制曲线图表的⽅法选择很多,下⾯我将介绍如何使⽤QtCharts绘制优雅图表。
本⽂的Demo⽀持点击Mark图标消隐曲线;数据点的突出显⽰;⿏标进⼊提⽰数值;数据驱动刷新显⽰;图表⾃动缩放,可移植性⽐较好。
需要说明Demo的编码环境是Qt Creator 5.8,使⽤Create5.2-5.6版本的⽤户,⽹上下载编译安装QtCharts库即可,5.7版本之后只需在.PRO⽂件中加⼊charts模块即可。
Demo显⽰效果如下:
⿏标进⼊提⽰数值:
perjury点击legend提⽰信息,可以消隐对应的曲线,如下图,点击曲线2的提⽰信息,曲线2消隐;再次点击,
曲线还原。
代码之路
主要由两个类组成,⼀个Callout类,⽤来显⽰数值的消息框,核⼼代码就是根据⿏标位置绘制提⽰框;⼀个baChart类,绘制整个图表,实现曲线显隐、更新数据重绘曲线等。
Callout.h
#include <QtCharts>
点读机英语教材下载
#include <QGraphicsItem>
#include <QFont>
QT_CHARTS_USE_NAMESPACE //相当于 using namespace QtCharts;
class Callout : public QGraphicsItem
{
public:
Callout(QChart* chart);
void tText(const QString &text); //消息框显⽰内容
void tAnchor(QPointF point); //消息框作下⾓坐标
void updateGeometry();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
protected:
void mouPressEvent(QGraphicsSceneMouEvent *event);
void mouMoveEvent(QGraphicsSceneMouEvent *event);
思源
private:
QString m_text;
QRectF m_textRect;
QRectF m_rect;
wanbangQPointF m_anchor;
QFont m_font;
QChart *m_chart;
};
Callout.cpp
Callout::Callout(QChart *chart): QGraphicsItem(chart), m_chart(chart)
{
}
void Callout::tText(const QString &text)
{
m_text = text;
QFontMetrics metrics(m_font);
m_textRect = metrics.boundingRect(QRect(0, 0, 150, 150), Qt::AlignLeft, m_text);
anslate(5,5);
prepareGeometryChange();
m_rect = m_textRect.adjusted(-5, -5, 5, 5);
}
void Callout::tAnchor(QPointF point)
{
m_anchor = point;
}
void Callout::updateGeometry()
{
prepareGeometryChange();
tPos(m_chart->mapToPosition(m_anchor) + QPoint(10, -50));
}
QRectF Callout::boundingRect() const
{
QPointF anchor = mapFromParent(m_chart->mapToPosition(m_anchor));
QRectF rect;
rect.tLeft(qMin(m_rect.left(), anchor.x()));
rect.tRight(qMax(m_rect.right(), anchor.x()));
rect.tTop(qMin(p(), anchor.y()));
rect.tBottom(qMax(m_rect.bottom(), anchor.y()));
return rect;
}
void Callout::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
QPainterPath path;
path.addRoundedRect(m_rect, 5, 5);
QPointF anchor = mapFromParent(m_chart->mapToPosition(m_anchor));
if (!ains(anchor))
{
QPointF point1, point2;
//建⽴锚点与矩形的相关联系
bool above = anchor.y() <= p();
bool aboveCenter = anchor.y() > p() && anchor.y() <= ().y();
bool belowCenter = anchor.y() > ().y() && anchor.y() <= m_rect.bottom();
joy2keybool below = anchor.y() > m_rect.bottom();
bool onLeft = anchor.x() <= m_rect.left();
bool leftOfCenter = anchor.x() > m_rect.left() && anchor.x() <= ().x();
bool rightOfCenter = anchor.x() > ().x() && anchor.x() <= m_rect.right();
bool onRight = anchor.x() > m_rect.right();
/
/获得最近的矩形⾓
// get the nearest m_rect corner.
qreal x = (onRight + rightOfCenter) * m_rect.width();
qreal y = (below + belowCenter) * m_rect.height();
bool cornerCa = (above && onLeft) || (above && onRight) || (below && onLeft) || (below && onRight);
bool cornerCa = (above && onLeft) || (above && onRight) || (below && onLeft) || (below && onRight);
bool vertical = qAbs(anchor.x() - x) > qAbs(anchor.y() - y);
qreal x1 = x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCa * !vertical * (onLeft * 10 - onRight * 20); qreal y1 = y + aboveCenter * 10 - belowCenter * 20 + cornerCa * vertical * (above * 10 - below * 20);; point1.tX(x1);
point1.tY(y1);
qreal x2 = x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCa * !vertical * (onLeft * 20 - onRight * 10);; qreal y2 = y + aboveCenter * 20 - belowCenter * 10 + cornerCa * vertical * (above * 20 - below * 10);; point2.tX(x2);
point2.tY(y2);
path.lineTo(anchor);
path.lineTo(point2);
path = path.simplified();
}
reckonpainter->tBrush(QColor(255,255,255));
painter->drawPath(path);
painter->drawText(m_textRect, m_text);
}
void Callout::mouPressEvent(QGraphicsSceneMouEvent *event)
{
snapeevent->tAccepted(true);
}
void Callout::mouMoveEvent(QGraphicsSceneMouEvent *event)
{
if(event->buttons() & Qt::LeftButton)
{
tPos(mapToParent(event->pos() - event->buttonDownPos(Qt::LeftButton)));
event->tAccepted(true);
}
el
{
event->tAccepted(fal);
}
}
fibc
bachart.h
#include <QtCharts>
both#include <QWidget>
#include <QGraphicsView>
#include <QScatterSeries>
#include <callout.h>
#include <QLegendMarker>
using namespace QtCharts;
//QT_CHARTS_USE_NAMESPACE
class baChart : public QGraphicsView
{
Q_OBJECT
public:
explicit baChart(QWidget *parent = 0);
~baChart();
protected:
void resizeEvent(QResizeEvent *event);
void mouMoveEvent(QMouEvent *event);
public slots:
void toolTip(QPointF point, bool state);
//控制曲线显隐
void removeSeries();
void connectMarkers();
void disconnectMarkers();
void handleMarkerClicked();
//更新数据重绘曲线和坐标轴
void chartdataSlot(QList<QList<QPoint> > dataList, float Xmin, float Xmax, float Ymin, float Ymax);
private:
QGraphicsSimpleTextItem *m_coordX;
QGraphicsSimpleTextItem *m_coordY;
QChart *m_chart;
Callout *m_tooltip;
QList<Callout*> m_callouts;
//控制曲线显隐
QList <QLineSeries*> m_ries;
QList <QScatterSeries*> m_scatterries;
};
display是什么意思bachart.cpp
baChart::baChart(QWidget *parent) : QGraphicsView(new QGraphicsScene, parent), m_coordX(0),m_coordY(0),m_chart(0),m_tooltip(0) {
tDragMode(QGraphicsView::NoDrag);
tVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
tHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//chart
m_chart = new QChart;
// m_chart->tMinimumSize(640, 480);
m_chart->tTitle("Hover the line to show callout and hide");
// m_chart->legend()->hide();
//添加数据,后⾯封装成⼀个接⼝
QLineSeries *ries = new QLineSeries;
ries->append(1,3);
ries->append(4,5);