QWT--数据游标

一、前言

在开发数据-曲线功能时,如果把曲线和数据分立开来,观测起来不是很方便。只显示曲线,虽然能观测到变化趋势,但是无法读到精确的值;只显示数据,虽然可以读到精确的值,但是无法直观的看出曲线的变化趋势。示波器通常会采用示数线(一根垂直于界面的直线)来读数,移动到哪,就显示该点的值,这样就中和了曲线和数据二者的优势,让用户使用起来很便捷。

其实之前就写过类似的功能,如下:
在这里插入图片描述
但是当时刚刚接触QWT,也没有图形视图框架的基础,当时不知道怎么索引画布上的图元,所以采用的是按钮的形式来移动数据游标,可以结合速度调节按钮来实现快慢移动,虽然实现了预期的功能,但是这样操作起来还是很不方便。

这次在之前的基础上做了一些改进,可以直接通过鼠标来移动数据游标,实现精确读数。


二、效果展示

在这里插入图片描述


三、思路分析

我们将数据游标逐步分解:1、对象;2、动作
1、对象
数据游标是一个自定义的Qwt图元,可以参考:QWT–自定义图元项

2、动作
很明显这是一个鼠标事件,我们只需要重写鼠标事件:

void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);

四、关键代码

自定义QWT图元类–数据游标线

#ifndef QWTVALUELINE_H
#define QWTVALUELINE_H

#include <qwt_plot_item.h>
#include <qwt_painter.h>

#include "DataDefine.h"

class QPainter;
class QPen;
class QFont;
class QwtScaleMap;
class QwtScaleDiv;

class QwtValueLine : public QwtPlotItem
{
public:
    QwtValueLine();

    QPointF ValueLine_Pos1;
    QPointF ValueLine_Pos2;
    QColor ValueLine_Color;

    virtual int rtti() const; //指定当前图元项代表的意义
    virtual void draw( QPainter *p,
        const QwtScaleMap &xMap, const QwtScaleMap &yMap,
        const QRectF &rect ) const; //自定义图元项绘制函数

    void set_ValueLine_Pos1(QPointF);
    void set_ValueLine_Pos2(QPointF);
    void set_ValueLine_Color(QColor);
};

#endif // QWTVALUELINE_H

#include "qwtvalueline.h"

QwtValueLine::QwtValueLine()
{
    ValueLine_Pos1 = QPointF(-1,-1);
    ValueLine_Pos2 = QPointF(-1,-1);
    ValueLine_Color = QColor(255,0,0);
}

int QwtValueLine::rtti() const //虚函数,指定当前图元项代表的意义
{
    return QwtPlotItem::Rtti_PlotUserItem + valueLine_item;
}
void QwtValueLine::draw( QPainter *p,
                  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
                  const QRectF &rect ) const //纯虚函数,自定义图元项绘制函数
{
    p->setRenderHints(QPainter::Antialiasing, true); //设置反锯齿
    p->setPen(QPen(ValueLine_Color,3));

    QwtPainter::drawLine(p,ValueLine_Pos1,ValueLine_Pos2);
}

void QwtValueLine::set_ValueLine_Pos1(QPointF pos1)
{
    this->ValueLine_Pos1 = pos1;
    this->itemChanged();
}
void QwtValueLine::set_ValueLine_Pos2(QPointF pos2)
{
    this->ValueLine_Pos2 = pos2;
    this->itemChanged();
}
void QwtValueLine::set_ValueLine_Color(QColor color)
{
    this->ValueLine_Color = color;
    this->itemChanged();
}


QwtPlot中重写鼠标事件

void PlotView::mousePressEvent(QMouseEvent *event)
{
    mousePressed = event->pos();    //物理坐标

    isSelected_valueLine = false;

    for(int i=0; i<this->itemList().size(); ++i) {
        if(this->itemList().at(i)->rtti() == QwtPlotItem::Rtti_PlotUserItem + valueLine_item) {
            valueLine = (QwtValueLine*)this->itemList()[i];
            //valueLine = dynamic_cast<QwtValueLine*>(this->itemList()[i]);
        }
    }

    if(valueLine != nullptr) {
        if(qAbs(mousePressed.x() - valueLine->ValueLine_Pos1.x()) <= 10) {
            isSelected_valueLine = true;
        }
    }
}

void PlotView::mouseMoveEvent(QMouseEvent *event)
{
    mouseMoved = event->pos();

}

void PlotView::mouseReleaseEvent(QMouseEvent *event)
{
    mouseReleased = event->pos();

    float moveDistance = 0.0;		//鼠标移动的物理距离
    int adjust_moveNum = 0;			//调整后移动的数据点数
    float adjust_moveLength = 0.0;	//调整后移动的物理距离

    //画布上0-1之间的物理距离
    int x1 = this->transform(QwtPlot::xBottom,0);
    int x2 = this->transform(QwtPlot::xBottom,1);
    int x_space = x2-x1;

    //数据个数、数据总物理长度、单个数据物理长度
    int N_data = parentWidget->parentWidget->data_chat_vec.at(0).time_vec.size();
    double M_length = parentWidget->parentWidget->stretch_delta_H*x_space;
    double single_data_length = M_length / N_data;

    //移动示数线
    if(isSelected_valueLine) {
        moveDistance = mouseReleased.x() - mousePressed.x();
        adjust_moveNum = moveDistance / single_data_length;         //调整后移动的数据个数
        adjust_moveLength = adjust_moveNum*single_data_length;      //调整后移动的物理距离

        if(valueLine != nullptr) {
            QPointF pos1 = QPointF(valueLine->ValueLine_Pos1.x()+adjust_moveLength,valueLine->ValueLine_Pos1.y());
            QPointF pos2 = QPointF(valueLine->ValueLine_Pos2.x()+adjust_moveLength,valueLine->ValueLine_Pos2.y());
			
			//示数线不能超出显示范围
            if(pos1.x() < single_data_length*10 || pos2.x() < single_data_length*10 || pos1.x() >= 100*x_space || pos2.x() >= 100*x_space) {
                return;
            
            //更新示数线坐标,重绘
            valueLine->set_ValueLine_Pos1(QPointF(valueLine->ValueLine_Pos1.x()+adjust_moveLength,valueLine->ValueLine_Pos1.y()));
            valueLine->set_ValueLine_Pos2(QPointF(valueLine->ValueLine_Pos2.x()+adjust_moveLength,valueLine->ValueLine_Pos2.y()));
            this->replot();
        }
    }
    isSelected_valueLine = false;

    //更新示数
    double valueLine_length = valueLine->ValueLine_Pos1.x();    //当前示数线x坐标
    int index = valueLine_length / single_data_length;          //当前示数线位置对应的数据索引下标

    for(int i=0; i<parentWidget->parentWidget->m_list_Value.at(parentWidget->parentWidget->m_tabWidget->currentIndex()).size(); ++i) {  //更新当前画布上的所有示数标签的读数
        double value = 0.0;
        if(index < parentWidget->parentWidget->data_chat_vec.at(parentWidget->parentWidget->m_tabWidget->currentIndex()).curve_vec.at(i).data_vec.size()) {
            value = parentWidget->parentWidget->data_chat_vec.at(parentWidget->parentWidget->m_tabWidget->currentIndex()).curve_vec.at(i).data_vec.at(index);
        }else {
            value = -1;
        }
        parentWidget->parentWidget->m_list_Value.at(parentWidget->parentWidget->m_tabWidget->currentIndex()).at(i)->setText(QString::number(value));
    }

}
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝勒里恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值