QtCharts的簡單用法(2)--Qt
阿新 • • 發佈:2018-12-14
前言
很多時候,我們用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<QPointF> 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<QPointF> points=m_series->points(); qreal max=m_axisY->max(); for(int i=0;i<m_points.size();i++) { if(m_points[i].y()>max) 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 <QtCharts/QChartGlobal>
#include <QtWidgets/QGraphicsItem>
#include <QtGui/QFont>
#include<QChart>
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 <QPainter>
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<QChartView>
#include<QGraphicsView>
#include<QMouseEvent>
#include<QWheelEvent>
#include<QChart>
#include <QtWidgets/QGraphicsScene>
#include <QtCharts/QChart>
#include <QtCharts/QLineSeries>
#include <QtCharts/QSplineSeries>
#include<QGraphicsLineItem>
#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<QDebug>
#include<QGraphicsView>
#include <QLegendMarker>
#include <QQueue>
#include <QtCore/QtMath>
#include<QApplication>
#include<QCategoryAxis>
#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<QAbstractSeries *> seriesList=m_chart->series();
QString text="";
for(int i=0;i<seriesList.size();i++){
QLineSeries* series=(QLineSeries*)seriesList.at(i);
QList<QPointF> points=series->points();
for(int j=0;j<points.size();j++){
QPointF curPoint=points.at(j) ;
if(curPoint.x()>pointX)
{
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<QLegendMarker*> (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<QAbstractSeries *> seriesList=m_chart->series();
for(int i=0;i<seriesList.size();i++){
QLineSeries* series=(QLineSeries*)seriesList.at(i);
if(series!=marker->series()){
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;
}
}
}
介面效果:
結束語
最近沒時間上網,這篇寫的不是很好,幾乎是貼程式碼。將就,有時間進行調整。