qt中使用qwt实现实时曲线显示

最近做一个飞控的上位机,需要实时在一个图中显示多条曲线,并且这些曲线还可以在任何时刻隐藏和显示。于是借鉴qgc地面站中显示mavlink消息的曲线显示方法,用qwt实现了这一功能。

最终效果


可以设置任意曲线是否显示,

还可以设置背景颜色。

滑动效果
qt中使用qwt实现实时曲线显示_第1张图片

问题分析:

首先,曲线图需要网格定义,曲线宽度,曲线颜色等基本的信息,可以写一个基类,把这些基本信息写到里面。然后在继承类中增加曲线添加,单条曲线显示,单条曲线隐藏,更新曲线数据等方法。最后,为了使曲线在图上运动起来,还需要一个队列来保存前多少时间的时序数据,这也用一个类来实现。

qwt配置:

首先下载qwt的源码,然后打开pro后缀的qt工程,进行编译(注意是32位还是64位)。编译完成后会出现qwtd.lib,qwt.lib,qwtd.dll,qwt.dll。
如果是5.9版本的msvc2015 64位,则把lib文件放到Qt5.9.0\5.9\msvc2015_64\lib目录下,把dll文件放到D:\Qt\Qt5.9.0\5.9\msvc2015_64\bin目录下。如果是32位,则放到32位对应的目录下。

同时会生成: qwt_designer_plugin.dll文件,这个文件必须是32位的,把dll文件放到Qt5.9.0\Tools\QtCreator\bin\plugins\designer目录下即可。这一步也可以不做,这样的话就不能拖控件实现布局,需要在代码中定义控件。

然后重启qt,打开界面设计,会看到有新的控件出现:
qt中使用qwt实现实时曲线显示_第2张图片
如果要使用qwt提高的图表,在新建的工程中还需要在pro文件中添加如下语句:

CONFIG(debug, debug|release) {
LIBS += D:\Qt\Qt5.9.0\5.9\msvc2015_64\lib\qwtd.lib
} else {
LIBS += D:\Qt\Qt5.9.0\5.9\msvc2015_64\lib\qwt.lib
}

DEFINES += QT_DLL QWT_DLL

代码:

储存曲线图基本信息的类,需要继承自QwtPlot

主要有这些成员

void appendData(QString dataname, quint64 ms, double value);
void setVisibleById(QString id, bool visible);
void hideCurve(QString id);
void showCurve(QString id);
void setCurveColor(QString id, QColor color);
void addCurve(QString id);

同时定义如下变量:

QMap _data;    //用于存放所以系列数据
QMap   _curves;    //用于存放所以曲线

添加曲线时:

void addCurve(QString id)
{
    QColor currentColor = getNextColor();

    // Create new curve and set style
    QwtPlotCurve* curve = new QwtPlotCurve(id);
    // Add curve to list
    _curves.insert(id, curve);

    curve->setStyle(QwtPlotCurve::Lines);
    curve->setPaintAttribute(QwtPlotCurve::FilterPoints, true);
    setCurveColor(id, currentColor);
    curve->setLegendAttribute(curve->LegendShowLine);
    curve->attach(this);

    // Create dataset
    TimeSerialData* dataset = new TimeSerialData();

    // Add dataset to list
    _data.insert(id, dataset);
}

显示和隐藏曲线:

void setVisibleById(QString id, bool visible)
{
    if(_curves.contains(id))
    {
        _curves.value(id)->setVisible(visible);
        if(visible)
            _curves.value(id)->attach(this);
        else
            _curves.value(id)->detach();
    }
}

void hideCurve(QString id)
{
    setVisibleById(id, false);
}

void showCurve(QString id)
{
    setVisibleById(id, true);
}

给曲线附加数据时:

void appendData(QString dataname, quint64 time, double value)
{
    datalock.lock();
    if(!data.contains(dataname))
        addCurve(dataname);
    TimeSerialData* dataset = _data.value(dataname);

    dataset->append(time, value);

    QwtPlotCurve* curve = _curves.value(dataname);
    curve->setRawSamples(dataset->getPlotX(), dataset->getPlotY(), dataset->getPlotCount());

    setAxisScale(QwtPlot::xBottom, dataset->getmsstart(), dataset->getmsstop(),10.0);
    setAxisScale(QwtPlot::yLeft,-30,30,5);
    datalock.unlock();
}

时间序列的类

头文件

#ifndef TIMESERIALDATA_H
#define TIMESERIALDATA_H
#include 
#include 

class TimeSerialData
{
public:
    TimeSerialData();

    void append(quint64 ms, double value);

    int getCount() const;

    const double* getPlotX() const;
    const double* getPlotY() const;
    int getPlotCount() const;

    int getmsstart(){return ms.at(0);}
    int getmsstop(){return ms.at(ms.size()-1);}

    QMutex dataMutex;
private:

    QVector ms;
    QVector value;
    double maxValue;
    double minValue;
    int count;
    int maxsize;
};

#endif // TIMESERIALDATA_H

cpp文件:

#include "timeserialdata.h"

TimeSerialData::TimeSerialData()
{
    count = 0;
    maxsize = 100;
    maxValue = -100000;
    minValue = 100000;
}

int TimeSerialData::getCount() const
{
    return count;
}

int TimeSerialData::getPlotCount() const
{
    if(count>maxsize)
        return maxsize;
    return count;
}

const double* TimeSerialData::getPlotX() const
{
    return ms.data();
}

const double* TimeSerialData::getPlotY() const
{
    return value.data();
}

void TimeSerialData::append(quint64 ms, double value)
{
    dataMutex.lock();
    count++;
    // Qt will automatically use a smart growth strategy: http://doc.qt.io/qt-5/containers.html#growth-strategies
    this->ms.append(ms);
    this->value.append(value);

    if(minValue > value) minValue = value;
    if(maxValue < value) maxValue = value;

    if(count >maxsize )
    {
        this->ms.pop_front();
        this->value.pop_front();
    }

    dataMutex.unlock();
}

该类主要用来储存时间序列的队列,只保存前100帧数据,使用QVector进行队列维护。可以计算当前数据坐标范围,返回需要显示的数据块指针。

你可能感兴趣的:(qt)