很多时候,我们用QtCharts不仅仅只是显示个线条趋势什么的,还需要一些小的功能,比如只显示某条线条,再比如让动态的线条停止滚动等。所以这篇博客就是介绍的这些东西,碎而杂。
本文主要介绍如下几个功能:
(1)静态模式(数据依旧接收,但线条静止;当退出当前模式,线条动态,并将之前的数据刷上去)
(2)横坐标为日期时间,如2018-06-25 14:35:45:000
(3)浮标的显示(跟示波器相似)
(1)静态模式:只要将接收到的数据缓存下(即找个容器存放下),退出此模式再刷上去就可以了。下面的代码有考虑上下限,可能有些地方不太完善。
private:
Ui::MainWindow *ui;
QChart *m_chart;
QDateTimeAxis* m_axisX;
QValueAxis* m_axisY;
QLineSeries* m_series;
QTimer m_timer;
QDateTime m_maxDateTime; //横轴时间最大值
QGraphicsLineItem* m_upperLineItem;
QGraphicsLineItem* m_lowerLineItem;
bool staticModelFlag; //静态模式biaoshi标识
QList m_points; //装静态时产生的数据
int m_seriesMaxSize; //series的数据容量
void MainWindow::handleTimeout()
{
qreal y=qrand() % 50; //随机产生的数值
QDateTime currentDateTime=QDateTime::currentDateTime();
QPointF point(QDateTime::currentDateTime().toMSecsSinceEpoch(),y);
if(staticModelFlag)
{//静态模式
m_points.push_back(point);
}else{
//非静态模式
QList points=m_series->points();
qreal max=m_axisY->max();
for(int i=0;imax)
max=m_points[i].y();
}
if(!m_points.isEmpty()){
points.append(m_points);
m_points.clear();
}
points.append(point);
//清除多余数据
while(points.size()>m_seriesMaxSize)
{
points.pop_front();
}
m_series->replace(points);
//重置x轴范围
if(currentDateTime>m_axisX->max())
{
QDateTime max=m_axisX->max();
if(max.toTime_t()==0)
{
m_maxDateTime=currentDateTime.addSecs(60);
m_axisX->setRange(currentDateTime,m_maxDateTime);
}else{
m_maxDateTime=currentDateTime;
m_axisX->setRange(m_maxDateTime.addSecs(-60),m_maxDateTime);
}
}
//重置y轴范围
m_axisY->setMax(qMax(max,y));
}
}
(2)横坐标为日期时间。这个功能很简单,修改下横轴就可以:将横轴从QValueAxis修改成QDateTimeAxis。
m_axisX=new QDateTimeAxis;
m_axisX->setTickCount(4);
m_axisX->setFormat("yyyy-MM-dd hh:mm:ss:zzz"); //设置格式
m_chart->addAxis(m_axisX, Qt::AlignBottom);
m_series->attachAxis(m_axisX);
m_axisY=new QValueAxis;
m_axisY->setTickCount(11);
m_axisY->setRange(0,40);
m_axisY->setLabelFormat("%i");
m_chart->addAxis(m_axisY,Qt::AlignLeft);
m_series->attachAxis(m_axisY);
下面给出以上两个小功能,结合在一起的界面效果。
(3)浮标的显示。这个功能我参考了Qt自带的示例Callout。这个部分将QChart与图像框架部分结合了起来。用到了类QGraphicsItem,QGraphicsLineItem,QGraphicsScene等。
浮标代码:
#ifndef CALLOUT_H
#define CALLOUT_H
#include
#include
#include
#include
QT_CHARTS_USE_NAMESPACE
class CallOut : public QGraphicsItem
{
public:
CallOut(QChart *parent);
void setText(const QString &text);
void setAnchor(QPointF point);
void updateGeometry();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget);
private:
QString m_text;
QRectF m_textRect;
QRectF m_rect;
QPointF m_anchor;
QFont m_font;
QChart *m_chart;
};
#endif // CALLOUT_H
#include "callout.h"
#include
CallOut::CallOut(QChart *chart):
QGraphicsItem(chart),
m_chart(chart)
{
}
void CallOut::setText(const QString &text)
{
m_text=text;
QFontMetrics metrics(m_chart->font());
m_textRect = metrics.boundingRect(QRect(0, 0, 150, 150), Qt::AlignLeft, m_text);
m_textRect.translate(5, 5);
prepareGeometryChange();
m_rect = m_textRect.adjusted(-5, -5, 5, 5);
}
void CallOut::setAnchor(QPointF point)
{
m_anchor=point;
}
void CallOut::updateGeometry()
{
prepareGeometryChange();
QPointF anchor;
anchor.setX(-m_rect.width()/2+m_anchor.x());
anchor.setY(m_chart->plotArea().height()/2);
setPos(anchor);
}
QRectF CallOut::boundingRect() const
{
QPointF anchor = mapFromParent(m_anchor);
QRectF rect;
rect.setLeft(qMin(m_rect.left(), anchor.x()));
rect.setRight(qMax(m_rect.right(), anchor.x()));
rect.setTop(qMin(m_rect.top(), anchor.y()));
rect.setBottom(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);
//path=path.simplified();
painter->setBrush(QColor(93,93,93,90));
painter->setPen(QPen(QColor(93,93,93,75)));
painter->drawPath(path);
painter->setPen(QPen(Qt::white));
painter->drawText(m_textRect,m_text);
}
视图:
#ifndef CHARTVIEW_H
#define CHARTVIEW_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"callout.h"
#include"chart.h"
QT_CHARTS_USE_NAMESPACE
class ChartView : public QChartView
{
Q_OBJECT
public:
ChartView(QWidget *parent = 0);
qreal getYValue(QPointF p1,QPointF p2,qreal x);
protected:
bool viewportEvent(QEvent *event)override;
void mousePressEvent(QMouseEvent *event)override;
void mouseMoveEvent(QMouseEvent *event)override;
void mouseReleaseEvent(QMouseEvent *event)override;
public slots:
void connectMarkers();
void handleMarkerClicked();
private:
QGraphicsLineItem* m_LineItem;
QGraphicsLineItem* m_topLineItem; //上限
QGraphicsLineItem* m_lowLineItem; //下限
CallOut* m_tooltip;
Chart *m_chart ;
bool m_isTouching;
public:
bool m_isBuoyShow;
};
#endif // CHARTVIEW_H
#include "chartview.h"
#include
#include
#include
#include
#include
#include
#include
#if _MSC_VER >=1600
#pragma execution_character_set("utf-8")
#endif
ChartView::ChartView(QWidget *parent) :
QChartView(parent),
m_tooltip(0),
m_isTouching(false),
m_isBuoyShow(false),
m_topLineItem(0),
m_lowLineItem(0)
{
m_chart=new Chart;
QLineSeries *series = new QLineSeries;
series->append(1, 3);
series->append(4, 5);
series->append(5, 4.5);
series->append(7, 1);
series->append(11, 2);
series->setName("参数一");
m_chart->addSeries(series);
QSplineSeries *series2 = new QSplineSeries;
series2->append(1.6, 1.4);
series2->append(2.4, 3.5);
series2->append(3.7, 2.5);
series2->append(7, 4);
series2->append(10, 2);
series2->setName("参数二");
m_chart->addSeries(series2);
m_chart->setTitle("Zoom in/out example");
//m_chart->setAnimationOptions(QChart::SeriesAnimations);
//m_chart->legend()->setAlignment(Qt::AlignRight);
m_chart->createDefaultAxes();
this->setChart(m_chart);
m_LineItem = new QGraphicsLineItem();
QPen pen=m_LineItem->pen();
pen.setColor(QColor(93,93,93,75));
pen.setWidth(3);
m_LineItem->setPen(pen);
this->scene()->addItem(m_LineItem);
m_LineItem->hide();
connectMarkers();
this->setRubberBand(QChartView::RectangleRubberBand);
}
qreal ChartView::getYValue(QPointF p1, QPointF p2, qreal x)
{
qreal y=(p2.y()-p1.y())/(p2.x()-p1.x())*(x-p1.x())+p1.y();
return y;
}
bool ChartView::viewportEvent(QEvent *event)
{
if (event->type() == QEvent::TouchBegin) {
m_isTouching = true;
chart()->setAnimationOptions(QChart::NoAnimation);
}
return QChartView::viewportEvent(event);
}
void ChartView::mousePressEvent(QMouseEvent *event)
{
if (m_isTouching)
return;
QChartView::mousePressEvent(event);
}
void ChartView::mouseMoveEvent(QMouseEvent *event)
{
if (m_isTouching)
return;
QChartView::mouseMoveEvent(event);
if(m_isBuoyShow){
bool flag=m_chart->plotArea().contains(event->pos());
if(flag)
{//在坐标轴中
if (m_tooltip == 0)
m_tooltip = new CallOut(m_chart);
qreal pointX=m_chart->mapToValue(event->pos()).x();
QList seriesList=m_chart->series();
QString text="";
for(int i=0;i points=series->points();
for(int j=0;jpointX)
{
if(j-1>=0){
qreal pointY=getYValue(curPoint, points[j-1],pointX);
QPointF point(pointX,pointY);
text+=tr("X%1:%2 Y%1:%4 \n").arg(i).arg(point.x()).arg(point.y());
}
break;
}
}
}
m_tooltip->setText(text);
m_tooltip->setAnchor(event->pos());
m_tooltip->setZValue(11);
m_tooltip->updateGeometry();
m_tooltip->show();
m_LineItem->setLine(QLineF(event->pos().x(),0,event->pos().x(),this->rect().height()));
m_LineItem->show();
}else{
if(m_tooltip!=0)
m_tooltip->hide();
m_LineItem->hide();
}
}
}
void ChartView::mouseReleaseEvent(QMouseEvent *event)
{
if (m_isTouching)
m_isTouching = false;
// Because we disabled animations when touch event was detected
// we must put them back on.
chart()->setAnimationOptions(QChart::SeriesAnimations);
QChartView::mouseReleaseEvent(event);
}
void ChartView::connectMarkers()
{
foreach (QLegendMarker* marker, m_chart->legend()->markers()) {
QObject::disconnect(marker, SIGNAL(clicked()), this, SLOT(handleMarkerClicked()));
QObject::connect(marker, SIGNAL(clicked()), this, SLOT(handleMarkerClicked()));
}
}
void ChartView::handleMarkerClicked()
{
QLegendMarker* marker = qobject_cast (sender());
Q_ASSERT(marker);
switch (marker->type())
{
case QLegendMarker::LegendMarkerTypeXY:
{
marker->setVisible(true);
qreal alpha;
QColor color;
QPen pen = marker->pen();
color = pen.color();
if(color.alphaF()==1.0){
//未点击
alpha=0.2;
QFont font=marker->font();
font.setBold(true);
marker->setFont(font);
}else {
//已点击
alpha=1.0;
QFont font=marker->font();
font.setBold(false);
marker->setFont(font);
}
QList seriesList=m_chart->series();
for(int i=0;iseries()){
QPen seriesPen=series->pen();
QColor color=seriesPen.color();
color.setAlphaF(alpha);
seriesPen.setColor(color);
series->setPen(seriesPen);
}
}
color.setAlphaF(alpha);
pen.setColor(color);
marker->setPen(pen);
break;
}
default:
{
qDebug() << "Unknown marker type";
break;
}
}
}
界面效果:
最近没时间上网,这篇写的不是很好,几乎是贴代码。将就,有时间进行调整。