QCustomPlot是一个开源的基于Qt的第三方绘图库,能够绘制漂亮的2D图形。
QCustomPlot的官方网址:https://www.qcustomplot.com/
从官网下载QCustomPlot的源文件,包括qcustomplot.h和qcustomplot.cpp。
 
本程序的源码下载地址: https://github.com/xiongxw/XCustomPlot.git
 
 
1 自定义鼠标显示跟随类XxwTracer和XxwTraceLine:
XxwTracer用于在图表中显示鼠标所在位置的x,y值
XxwTraceLine用于在图中显示水平或垂直的虚线
头文件XxwTracer.h
#ifndef MYTRACER_H
#define MYTRACER_H #include <QObject>
#include "qcustomplot.h" ///
/// \brief The XxwTracer class:在图表中显示鼠标所在位置的x,y值的追踪显示器
///
class XxwTracer : public QObject
{
Q_OBJECT public:
enum TracerType
{
XAxisTracer,//依附在x轴上显示x值
YAxisTracer,//依附在y轴上显示y值
DataTracer//在图中显示x,y值
};
explicit XxwTracer(QCustomPlot *_plot, TracerType _type, QObject *parent = Q_NULLPTR);
~XxwTracer();
void setPen(const QPen &pen);
void setBrush(const QBrush &brush);
void setText(const QString &text);
void setLabelPen(const QPen &pen);
void updatePosition(double xValue, double yValue);
void setVisible(bool m_visible); protected:
bool m_visible;//是否可见
TracerType m_type;//类型
QCustomPlot *m_plot;//图表
QCPItemTracer *m_tracer;//跟踪的点
QCPItemText *m_label;//显示的数值
QCPItemLine *m_arrow;//箭头
}; ///
/// \brief The XxwCrossLine class:用于显示鼠标移动过程中的鼠标位置的直线
///
class XxwTraceLine : public QObject
{
public:
enum LineType
{
VerticalLine,//垂直线
HorizonLine, //水平线
Both//同时显示水平和垂直线
};
explicit XxwTraceLine(QCustomPlot *_plot, LineType _type = VerticalLine, QObject *parent = Q_NULLPTR);
~XxwTraceLine();
void initLine();
void updatePosition(double xValue, double yValue); void setVisible(bool vis)
{
if(m_lineV)
m_lineV->setVisible(vis);
if(m_lineH)
m_lineH->setVisible(vis);
} protected:
bool m_visible;//是否可见
LineType m_type;//类型
QCustomPlot *m_plot;//图表
QCPItemStraightLine *m_lineV; //垂直线
QCPItemStraightLine *m_lineH; //水平线
}; #endif // MYTRACER_H

源文件MyTracer.cpp

#include "MyTracer.h"

XxwTracer::XxwTracer(QCustomPlot *_plot, TracerType _type, QObject *parent)
: QObject(parent),
m_plot(_plot),
m_type(_type)
{
m_visible = true;
m_tracer = Q_NULLPTR;// 跟踪的点
m_label = Q_NULLPTR;// 显示的数值
m_arrow = Q_NULLPTR;// 箭头
if (m_plot)
{
QColor clrDefault(Qt::red);
QBrush brushDefault(Qt::NoBrush);
QPen penDefault(clrDefault);
// penDefault.setBrush(brushDefault);
penDefault.setWidthF(0.5); m_tracer = new QCPItemTracer(m_plot);
m_tracer->setStyle(QCPItemTracer::tsCircle);
m_tracer->setPen(penDefault);
m_tracer->setBrush(brushDefault); m_label = new QCPItemText(m_plot);
m_label->setLayer("overlay");
m_label->setClipToAxisRect(false);
m_label->setPadding(QMargins(, , , ));
m_label->setBrush(brushDefault);
m_label->setPen(penDefault);
m_label->position->setParentAnchor(m_tracer->position);
// m_label->setFont(QFont("宋体", 8));
m_label->setFont(QFont("Arial", ));
m_label->setColor(clrDefault);
m_label->setText(""); m_arrow = new QCPItemLine(m_plot);
QPen arrowPen(clrDefault, );
m_arrow->setPen(penDefault);
m_arrow->setLayer("overlay");
m_arrow->setClipToAxisRect(false);
m_arrow->setHead(QCPLineEnding::esSpikeArrow);//设置头部为箭头形状 switch (m_type)
{
case XAxisTracer:
{
m_tracer->position->setTypeX(QCPItemPosition::ptPlotCoords);
m_tracer->position->setTypeY(QCPItemPosition::ptAxisRectRatio);
m_tracer->setSize();
m_label->setPositionAlignment(Qt::AlignTop | Qt::AlignHCenter); m_arrow->end->setParentAnchor(m_tracer->position);
m_arrow->start->setParentAnchor(m_arrow->end);
m_arrow->start->setCoords(, );//偏移量
break;
}
case YAxisTracer:
{
m_tracer->position->setTypeX(QCPItemPosition::ptAxisRectRatio);
m_tracer->position->setTypeY(QCPItemPosition::ptPlotCoords);
m_tracer->setSize();
m_label->setPositionAlignment(Qt::AlignRight | Qt::AlignHCenter); m_arrow->end->setParentAnchor(m_tracer->position);
m_arrow->start->setParentAnchor(m_label->position);
m_arrow->start->setCoords(-, );//偏移量
break;
}
case DataTracer:
{
m_tracer->position->setTypeX(QCPItemPosition::ptPlotCoords);
m_tracer->position->setTypeY(QCPItemPosition::ptPlotCoords);
m_tracer->setSize(); m_label->setPositionAlignment(Qt::AlignLeft | Qt::AlignVCenter); m_arrow->end->setParentAnchor(m_tracer->position);
m_arrow->start->setParentAnchor(m_arrow->end);
m_arrow->start->setCoords(, );
break;
}
default:
break;
}
setVisible(false);
}
} XxwTracer::~XxwTracer()
{
if(m_plot)
{
if (m_tracer)
m_plot->removeItem(m_tracer);
if (m_label)
m_plot->removeItem(m_label);
if (m_arrow)
m_plot->removeItem(m_arrow);
}
} void XxwTracer::setPen(const QPen &pen)
{
if(m_tracer)
m_tracer->setPen(pen);
if(m_arrow)
m_arrow->setPen(pen);
} void XxwTracer::setBrush(const QBrush &brush)
{
if(m_tracer)
m_tracer->setBrush(brush);
} void XxwTracer::setLabelPen(const QPen &pen)
{
if(m_label)
{
m_label->setPen(pen);
m_label->setBrush(Qt::NoBrush);
m_label->setColor(pen.color());
}
} void XxwTracer::setText(const QString &text)
{
if(m_label)
m_label->setText(text);
} void XxwTracer::setVisible(bool vis)
{
m_visible = vis;
if(m_tracer)
m_tracer->setVisible(m_visible);
if(m_label)
m_label->setVisible(m_visible);
if(m_arrow)
m_arrow->setVisible(m_visible);
} void XxwTracer::updatePosition(double xValue, double yValue)
{
if (!m_visible)
{
setVisible(true);
m_visible = true;
} if (yValue > m_plot->yAxis->range().upper)
yValue = m_plot->yAxis->range().upper; switch (m_type)
{
case XAxisTracer:
{
m_tracer->position->setCoords(xValue, );
m_label->position->setCoords(, );
m_arrow->start->setCoords(, );
m_arrow->end->setCoords(, );
setText(QString::number(xValue));
break;
}
case YAxisTracer:
{
m_tracer->position->setCoords(, yValue);
m_label->position->setCoords(-, );
// m_arrow->start->setCoords(20, 0);
// m_arrow->end->setCoords(0, 0);
setText(QString::number(yValue));
break;
}
case DataTracer:
{
m_tracer->position->setCoords(xValue, yValue);
m_label->position->setCoords(, );
setText(QString("x:%1,y:%2").arg(xValue).arg(yValue));
break;
}
default:
break;
}
} XxwTraceLine::XxwTraceLine(QCustomPlot *_plot, LineType _type, QObject *parent)
: QObject(parent),
m_type(_type),
m_plot(_plot)
{
m_lineV = Q_NULLPTR;
m_lineH = Q_NULLPTR;
initLine();
} XxwTraceLine::~XxwTraceLine()
{
if(m_plot)
{
if (m_lineV)
m_plot->removeItem(m_lineV);
if (m_lineH)
m_plot->removeItem(m_lineH);
}
} void XxwTraceLine::initLine()
{
if(m_plot)
{
QPen linesPen(Qt::red, , Qt::DashLine); if(VerticalLine == m_type || Both == m_type)
{
m_lineV = new QCPItemStraightLine(m_plot);//垂直线
m_lineV->setLayer("overlay");
m_lineV->setPen(linesPen);
m_lineV->setClipToAxisRect(true);
m_lineV->point1->setCoords(, );
m_lineV->point2->setCoords(, );
} if(HorizonLine == m_type || Both == m_type)
{
m_lineH = new QCPItemStraightLine(m_plot);//水平线
m_lineH->setLayer("overlay");
m_lineH->setPen(linesPen);
m_lineH->setClipToAxisRect(true);
m_lineH->point1->setCoords(, );
m_lineH->point2->setCoords(, );
}
}
} void XxwTraceLine::updatePosition(double xValue, double yValue)
{
if(VerticalLine == m_type || Both == m_type)
{
if(m_lineV)
{
m_lineV->point1->setCoords(xValue, m_plot->yAxis->range().lower);
m_lineV->point2->setCoords(xValue, m_plot->yAxis->range().upper);
}
} if(HorizonLine == m_type || Both == m_type)
{
if(m_lineH)
{
m_lineH->point1->setCoords(m_plot->xAxis->range().lower, yValue);
m_lineH->point2->setCoords(m_plot->xAxis->range().upper, yValue);
}
}
}
2 自定义的图表类XCustomPlot
XCustomPlot是基于QCustomPlot二次开发的图表类,在鼠标移动过程中动态显示曲线上点的值。
头文件XCustomPlot.h
#ifndef XCUSTOMPLOT_H
#define XCUSTOMPLOT_H #include "XxwTracer.h"
#include "qcustomplot.h"
#include <QObject>
#include <QList> class XxwCustomPlot:public QCustomPlot
{
Q_OBJECT public:
XxwCustomPlot(QWidget *parent = ); protected:
virtual void mouseMoveEvent(QMouseEvent *event); public:
///
/// \brief 设置是否显示鼠标追踪器
/// \param show:是否显示
///
void showTracer(bool show)
{
m_isShowTracer = show;
if(m_xTracer)
m_xTracer->setVisible(m_isShowTracer);
foreach (XxwTracer *tracer, m_dataTracers)
{
if(tracer)
tracer->setVisible(m_isShowTracer);
}
if(m_lineTracer)
m_lineTracer->setVisible(m_isShowTracer);
} ///
/// \brief 是否显示鼠标追踪器
/// \return
///
bool isShowTracer(){return m_isShowTracer;}; private:
bool m_isShowTracer;//是否显示追踪器(鼠标在图中移动,显示对应的值)
XxwTracer *m_xTracer;//x轴
XxwTracer *m_yTracer;//y轴
QList<XxwTracer *> m_dataTracers;//
XxwTraceLine *m_lineTracer;//直线
}; #endif // XCUSTOMPLOT_H

源文件XCustomPlot.h

#include "XxwCustomPlot.h"

XxwCustomPlot::XxwCustomPlot(QWidget *parent)
:QCustomPlot(parent)
,m_isShowTracer(false)
,m_xTracer(Q_NULLPTR)
,m_yTracer(Q_NULLPTR)
,m_dataTracers(QList<XxwTracer *>())
,m_lineTracer(Q_NULLPTR)
{
} void XxwCustomPlot::mouseMoveEvent(QMouseEvent *event)
{
QCustomPlot::mouseMoveEvent(event); if(m_isShowTracer)
{
//当前鼠标位置(像素坐标)
int x_pos = event->pos().x();
int y_pos = event->pos().y(); //像素坐标转成实际的x,y轴的坐标
float x_val = this->xAxis->pixelToCoord(x_pos);
float y_val = this->yAxis->pixelToCoord(y_pos); if(Q_NULLPTR == m_xTracer)
m_xTracer = new XxwTracer(this, XxwTracer::XAxisTracer);//x轴
m_xTracer->updatePosition(x_val, y_val); if(Q_NULLPTR == m_yTracer)
m_yTracer = new XxwTracer(this, XxwTracer::YAxisTracer);//y轴
m_yTracer->updatePosition(x_val, y_val); int nTracerCount = m_dataTracers.count();
int nGraphCount = graphCount();
if(nTracerCount < nGraphCount)
{
for(int i = nTracerCount; i < nGraphCount; ++i)
{
XxwTracer *tracer = new XxwTracer(this, XxwTracer::DataTracer);
m_dataTracers.append(tracer);
}
}
else if(nTracerCount > nGraphCount)
{
for(int i = nGraphCount; i < nTracerCount; ++i)
{
XxwTracer *tracer = m_dataTracers[i];
if(tracer)
{
tracer->setVisible(false);
}
}
}
for (int i = ; i < nGraphCount; ++i)
{
XxwTracer *tracer = m_dataTracers[i];
if(!tracer)
tracer = new XxwTracer(this, XxwTracer::DataTracer);
tracer->setVisible(true);
tracer->setPen(this->graph(i)->pen());
tracer->setBrush(Qt::NoBrush);
tracer->setLabelPen(this->graph(i)->pen());
auto iter = this->graph(i)->data()->findBegin(x_val);
double value = iter->mainValue();
// double value = this->graph(i)->data()->findBegin(x_val)->value;
tracer->updatePosition(x_val, value);
} if(Q_NULLPTR == m_lineTracer)
m_lineTracer = new XxwTraceLine(this,XxwTraceLine::Both);//直线
m_lineTracer->updatePosition(x_val, y_val); this->replot();//曲线重绘
}
}

3 使用自定义图表类XCustomPlot

在需要绘图的地方使用,代码如下:

  m_customPlot = new XxwCustomPlot();
m_customPlot->showTracer(true); // add title layout element:
m_customPlot->plotLayout()->insertRow();
m_customPlot->plotLayout()->addElement(, , new QCPTextElement(m_customPlot, "标题", QFont("黑体", , QFont::Bold))); m_customPlot->legend->setVisible(true);
QFont legendFont = font(); // start out with MainWindow's font..
legendFont.setPointSize(); // and make a bit smaller for legend
m_customPlot->legend->setFont(legendFont);
m_customPlot->legend->setBrush(QBrush(QColor(,,,)));
// by default, the legend is in the inset layout of the main axis rect. So this is how we access it to change legend placement:
m_customPlot->axisRect()->insetLayout()->setInsetAlignment(, Qt::AlignTop|Qt::AlignCenter); // make left and bottom axes always transfer their ranges to right and top axes:
connect(m_customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), m_customPlot->xAxis2, SLOT(setRange(QCPRange)));
connect(m_customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), m_customPlot->yAxis2, SLOT(setRange(QCPRange))); // Allow user to drag axis ranges with mouse, zoom with mouse wheel and select graphs by clicking:
m_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); // generate some data:
int nCount = ;
QVector<double> x(nCount), y0(nCount), y1(nCount); // initialize with entries 0..100
for (int i = ; i < nCount; ++i)
{
x[i] = i; // x goes from -1 to 1
y0[i] = qSin(i * 10.0f / nCount); //sin
y1[i] = qCos(i * 10.0f / nCount); //cos
}
// create graph and assign data to it:
QPen pen;
int i = ;
QCPGraph *pGraph = m_customPlot->addGraph();
// m_customPlot->graph(0)->setData(x, y0);
pGraph->setName("sin曲线");
pGraph->setData(x,y0);
pGraph->setPen(QPen(Qt::blue)); pGraph = m_customPlot->addGraph();
// m_customPlot->graph(0)->setData(x, y0);
pGraph->setName("cos曲线");
pGraph->setData(x,y1);
pGraph->setPen(QPen(Qt::darkYellow)); // give the axes some labels:
m_customPlot->xAxis->setLabel("x");
m_customPlot->yAxis->setLabel("y"); // set axes ranges, so we see all data:
// m_customPlot->xAxis->setRange(-1, 1);
// m_customPlot->yAxis->setRange(0, 1);
m_customPlot->rescaleAxes(true); m_customPlot->replot();

4 效果图

本程序的源码下载地址: https://github.com/xiongxw/XCustomPlot.git

采用Qt快速绘制多条曲线(折线),跟随鼠标动态显示线上点的值(基于Qt的开源绘图控件QCustomPlot进行二次开发)的更多相关文章

  1. qt超强精美绘图控件 - QCustomPlot一览 及 安装使用教程

    1.概述 QCustomPlot 是一个超强超小巧的qt绘图类,非常漂亮,非常易用,只需要加入一个qcustomplot.h和qcustomplot.cpp文件即可使用,远比qwt方便和漂亮,可以自己 ...

  2. paper 139:qt超强绘图控件qwt - 安装及配置

    qwt是一个基于LGPL版权协议的开源项目, 可生成各种统计图.它为具有技术专业背景的程序提供GUI组件和一组实用类,其目标是以基于2D方式的窗体部件来显示数据, 数据源以数值,数组或一组浮点数等方式 ...

  3. C# Charts绘制多条曲线

    一.创建winform工程 拖拽控件Chart 二.比如要绘制俩条曲线,设置Chart控件的属性Series 三.chart的属性根据自己的业务需求设计,我这里只设置了图标类型 代码: using S ...

  4. VS2010 使用TeeChart绘图控件 - 之二 - 绘制图形(折线图,柱状图)

    1.前期准备 具体可见VS2010 使用TeeChart绘图控件 - 之一 控件和类的导入 1. 1 添加TeeChart控件,给控件添加变量m_TeeChart 添加TeeChart控件,右击控件, ...

  5. qt超强绘图控件qwt - 安装及配置

    qwt是一个基于LGPL版权协议的开源项目, 可生成各种统计图.它为具有技术专业背景的程序提供GUI组件和一组实用类,其目标是以基于2D方式的窗体部件来显示数据, 数据源以数值,数组或一组浮点数等方式 ...

  6. MSChart绘图控件中折线图和柱形图画法

    首先在前台拖入一个名为chart1的MSChart控件 //折线图 string strLegend = "Legend1"; Legend lg = new Legend(str ...

  7. 使用C#三维绘图控件快速搭建DXF查看程序

    本例使用AnyCAD .Net三维图形控件快速实现一个DXF文件的读取.显示.导出JPG.PNG.PDF的应用. 代码: using System; using System.Collections. ...

  8. Qt绘图控件qwt绘制等比例坐标图

    需要用到QwtPlotRescaler类,用法如下: QwtPlotRescaler *plotRescaler = new QwtPlotRescaler(canvas, yLeft, QwtPlo ...

  9. C#.NET常见问题(FAQ)-如何使用2D绘图控件ZedGraph绘制坐标轴和坐标曲线

    添加数据:示例添加了一条sin曲线和一条cos曲线,注意cos曲线比sin曲线点更密集(可以用这种方式控制点的采样疏密程度)   默认显示效果如下图所示,可以框选一个部分看放大效果   右击某个点可以 ...

随机推荐

  1. MFC优秀博客记录 鸡啄米

    最近在学习和利用C++ MFC做一些小的应用,发现鸡啄米先生的教程很不错适合新手,在这就把自己实现的一些小demo分享一下: C++编程入门系列之目录和总结 第一部分:C++编程概述 第二部分:C++ ...

  2. HDU1254:推箱子(bfs+dfs)

    传送门 题意 给出一副图 0.空地1.墙2.箱子3.目的地4.人所在的位置 问最少几步能将箱子推到目的地 分析 这道题难度略大(菜鸡),首先用vis[bx][by][mx][my]记录当箱子(bx,b ...

  3. JavaScript中this的使用方法总结

    JavaScript中this的使用方法总结 在JavaScript中,this的使用分为四种场景,具体请参考阮一峰老师关于this的讲解 第一种情况是纯函数使用 var x =1 ; functio ...

  4. Golang bash脚本自动创建一个go工程

    原作者的代码里面,存在智能引号问题,所以他的代码并不能正常运行: 这个是我微调后的版本. 代码如下: #!/bin/bash #————————————– # Module : mk_go_pro.s ...

  5. CentOS安装GlassFish4.0 配置JDBC连接MySQL

    转自:http://linux.it.net.cn/CentOS/course/2014/0724/3319.html 版本glassfish-4.0.zip 1.解压,拷贝到指定安装路径   unz ...

  6. 450 Delete Node in a BST 删除二叉搜索树中的结点

    详见:https://leetcode.com/problems/delete-node-in-a-bst/description/ C++: /** * Definition for a binar ...

  7. APP多渠道打包

    多渠道打包的概念: 打包是指使用证书文件对app签名生成一个apk文件. 多渠道打包指的就是我们的app在开发完成之后需要投放到不同的市场,比如说Google市场.百度市场等,为了统计应用在各个市场的 ...

  8. framework7 点取消后还提交表单解决方案

    $$('form.ajax-submit').on('submitted', function (e) { var xhr = e.detail.xhr; // actual XHR object v ...

  9. Xml学习笔记(1)

    不同的xml文档构可能要用到不同的方法进行解析这里用到的是例如<student name="张三" id="1" sex="男"/&g ...

  10. node入门(二)——gulpfile.js初探

    本文关于gulpfile.js怎么写,利于完成个性化需求.本文开发环境默认已安装node,详情参考<node入门(一)——安装>. 一.安装gulp npm install -g gulp ...