先来个动图看看效果:
支持鼠标平移、滚轮缩放、框选放大、取消框选、一键全显、单击显示xy坐标值。。等
平移功能是QCustomPlot自带的功能,参见我的该系列前面的博文。框选放大、全显等功能在另一篇博文中也讲到了。
这里只讲2个知识点:1、显示鼠标指向的点坐标,2、实时滚动
1、箭头指向要显示的坐标点,代码步骤:
(1)添加新类,继承QCustomPlot
添加private成员变量:
QCPItemText *textLabel;//单击时提示信息框 QCPItemLine *arrow;//提示信息的箭头 在构造中初始化他俩:
//下面这一段是从QCustomPlot官网抄来的 /*显示数值的提示框*/ textLabel = new QCPItemText(this);
textLabel->setPositionAlignment(Qt::AlignTop|Qt::AlignHCenter);//方框置于上部中间
textLabel->position->setType(QCPItemPosition::ptAxisRectRatio);
textLabel->position->setCoords(0.5, 0); // place position at center/top of axis
rect textLabel->setFont(QFont(font().family(), 16)); // 字体
textLabel->setPen(QPen(Qt::black)); // 颜色 //指向数值的箭头: arrow = new
QCPItemLine(this);
arrow->start->setParentAnchor(textLabel->bottom);//箭头起点位于提示框的下边框中点
//arrow->end->setCoords(4, 1.6); // 设置箭头的终点
arrow->setHead(QCPLineEnding::esSpikeArrow);//箭头类型
textLabel->setVisible(false);//提示框不可见 arrow->setVisible(false);//箭头不可见
(2)重写鼠标按下/弹起事件
void MultiCurvesPlot::mousePressEvent(QMouseEvent *event) {
//重写后,仍然要使父类的函数,否则自带的拖动功能等就失效了 QCustomPlot::mousePressEvent(event);//父类的函数
if(event->buttons() & Qt::LeftButton)//按下鼠标左键 {
textLabel->setVisible(true);//提示框可见 arrow->setVisible(true);//箭头可见 double x =
xAxis->pixelToCoord(event->pos().x());//鼠标坐标转化为XY轴的坐标 double y =
yAxis->pixelToCoord(event->pos().y()); arrow->end->setCoords(x, y); // 设置箭头的终点
QString xTime = QDateTime::fromMSecsSinceEpoch(x *
1000.0).toString("hh:mm:ss.zzz");//把单击处的X值转换为时间String
textLabel->setText(QString("x = %1\ny=%2").arg(xTime).arg(y));//显示XY值 } } void
MultiCurvesPlot::mouseReleaseEvent(QMouseEvent *event) {
QCustomPlot::mouseReleaseEvent(event); if(event->button() ==
Qt::LeftButton)//左键弹起 { textLabel->setVisible(false);//隐藏数值方框和箭头
arrow->setVisible(false); } }
2、实时滚动的曲线
我们要做的就两点:1、向graph中添加新的点 this->graph(graphIdx)->addData(currentTime, y);
2、实时修改X轴的显示范围
在我这个例子中,X轴是实时时间,所以,要想使曲线实时滚动,只要把X轴的显示范围实时修改为:从<当前时间-当前X轴的显示宽度>到<当前时间>即可,
这样曲线就会滚动起来。其中,当前X轴的显示宽度可以从xAxis->range().size()读取。
注意:如果我们接收到的数据点过于频繁,我们不应该每收到一个点都要刷新图像,那样程序效率太低,也没必要。一般设置每30ms刷新一次就足够流畅了,毕竟我们下载的普通电影也就30帧每秒。
因此,我们在一个30ms定时器的槽函数中来做:修改X轴的显示范围+刷新图像。
代码步骤如下:
(1)在构造函数中启动QWidget自带的定时器
startTimer(30, Qt::CoarseTimer);//每30ms触发一次timeEvent事件
(2)重写void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE;函数来响应这个定时器的超时事件:
void MultiCurvesPlot::timerEvent(QTimerEvent *event) { Q_UNUSED(event);
if(autoScroll)//如果启动了自动滚动功能 { double curSeclf =
(double)(QDateTime::currentMSecsSinceEpoch()) /
1000.0;//读取当前时间(因为QCustomPlot支持的时间值的ms值在小数位,所以/1000.0了)
this->xAxis->setRange(curSeclf - xAxis->range().size(), curSeclf);//实时调整X轴的显示范围
} this->replot();//刷新图像 }
代码就这些,非常简单。
群号在左边。