用qwt绘制AD波形

来源:互联网 发布:南风知我意2 全文阅读 编辑:程序博客网 时间:2024/04/28 08:56

引子

      项目终于快完成了,现在开始整理下代码,总结下,今天先分享下关于使用如何用QWT绘制波形,先把图给贴出来。

绘制AD数据

关于QWT

     以下源于百度百科“QWT全称是Qt Widgets for Technical Applications,是一个基于LGPL版权协议的开源项目,可生成各种统计图。它为具有技术专业背景的程序提供GUI组件和一组实用类,其目标是以基于2D方式的窗体部件来显示数据,数据源以数值,数组或一组浮点数等方式提供,输出方式可以是Curves(曲线),Slider(滚动条),Dials(圆盘),Compasses(仪表盘)等等。该工具库基于Qt开发,所以也继承了Qt的跨平台特性。”

    我使用的是qwt-6.0.0-rc5,可以到官网下载http://qwt.sourceforge.net/,具体的安装和集成过程可以参照http://www.cuteqt.com/blog/?p=994这个贴子。

源码

“AdPlot.h”

 1: #ifndef ADPLOT_H
 2: #define ADPLOT_H
 3:  
 4: #include <QWidget>
 5: #include <qwt_plot_curve.h>
 6: #include <qfile.h>
 7: #include <qwt_plot_magnifier.h>
 8:  
 9: namespace Ui {
 10: class AdPlot;
 11: }
 12:  
 13: class AdPlot : public QWidget
 14: {
 15: Q_OBJECT
 16:  
 17: public:
 18: explicit AdPlot(QWidget *parent = 0);
 19: //要绘制的AD数据,X-时间,Y-电压值 
 20: void readAdData(QVector< double > &xData,
 21: QVector< double > &yData);
 22: void setTitleString(QString title);
 23: void setTimerStop();
 24:  
 25: ~AdPlot();
 26: public slots:
 27: //节点打开的AD数据的文件名 
 28: void setFileName(QString filename);
 29: //绘制AD数据 
 30: void plotAdCurve();
 31: private:
 32: Ui::AdPlot *ui;
 33: QwtPlotCurve *p_adplot;
 34: QVector< double > xData;
 35: QVector< double > yData;
 36: QFile *localFile;
 37: //文件偏移量 
 38: qint64 offset;
 39: double time;
 40: QString m_filename;
 41: QwtPlotMagnifier *PM;
 42: //当前X轴最大的范围 
 43: int xMaxScale;
 44:  
 45: QTimer *adPlotTimer;
 46:  
 47: QString m_title;
 48: };
 49:  
 50: #endif // ADPLOT_H 

 

    头文件没什么好说的,说明一下offset这个变量,它是用来保存当前的读取到的文件位置,而xData和yData分别储存时间和电压值。

“AdPlot.cpp”

 1: #include "adplot.h" 
 2: #include "ui_adplot.h" 
 3: #include <QtGui/QApplication>
 4: #include <qapplication.h>
 5: #include <qlayout.h>
 6: #include <qlabel.h>
 7: #include <qpainter.h>
 8: #include <qwt_plot_layout.h>
 9: #include <qwt_plot_curve.h>
 10: #include <qwt_scale_draw.h>
 11: #include <qwt_scale_widget.h>
 12: #include <qwt_legend.h>
 13: #include <qwt_legend_item.h>
 14: #include <QTime>
 15: #include <qtimer.h>
 16: #include <QMessageBox>
 17: #include <qcolor.h>
 18: #include <qwt_plot_zoomer.h>
 19:  
 20: class TimeScaleDraw: public QwtScaleDraw
 21: {
 22: public:
 23: TimeScaleDraw(const QTime &base):
 24: baseTime(base)
 25: {
 26: }
 27:  
 28: virtual QwtText label(double v) const 
 29: {
 30: QTime upTime = baseTime.addSecs((int)v);
 31: return upTime.toString();
 32: }
 33:  
 34: private:
 35: QTime baseTime;
 36: };
 37:  
 38:  
 39: AdPlot::AdPlot(QWidget *parent) :
 40: QWidget(parent),
 41: ui(new Ui::AdPlot)
 42: {
 43: ui->setupUi(this);
 44: ui->qwtPlot->setAutoReplot(false);
 45: QTime curTime;
 46: curTime = curTime.currentTime();
 47:  
 48:  
 49:  
 50: QwtLegend *legend = new QwtLegend;
 51: legend->setItemMode(QwtLegend::CheckableItem);
 52: //ui->qwtPlot->insertLegend(legend, QwtPlot::RightLegend); 
 53: ui->qwtPlot->setAxisTitle(QwtPlot::xBottom, " System Uptime [h:m:s]");
 54: ui->qwtPlot->setAxisScaleDraw(QwtPlot::xBottom,
 55: new TimeScaleDraw(curTime));
 56: ui->qwtPlot->setAxisScale(QwtPlot::xBottom, 0, xMaxScale = 5);
 57: ui->qwtPlot->setAxisLabelAlignment(QwtPlot::xBottom, Qt::AlignLeft | Qt::AlignBottom);
 58:  
 59: QwtScaleWidget *scaleWidget = ui->qwtPlot->axisWidget(QwtPlot::xBottom);
 60: const int fmh = QFontMetrics(scaleWidget->font()).height();
 61: scaleWidget->setMinBorderDist(0, fmh / 2);
 62:  
 63: ui->qwtPlot->setAxisTitle(QwtPlot::yLeft, "V");
 64: ui->qwtPlot->setAxisScale(QwtPlot::yLeft, 0, 3);
 65: p_adplot = new QwtPlotCurve();
 66: QColor c = Qt::red;
 67: c.setAlpha(150);
 68: p_adplot->setPen(c);
 69:  
 70: p_adplot->attach(ui->qwtPlot);
 71: //PM = new QwtPlotMagnifier(ui->qwtPlot->canvas()); 
 72: QwtPlotZoomer* zoomer = new QwtPlotZoomer( ui->qwtPlot->canvas() );
 73: zoomer->setRubberBandPen( QColor( Qt::black ) );
 74: zoomer->setTrackerPen( QColor( Qt::black ) );
 75: zoomer->setMousePattern(QwtEventPattern::MouseSelect2,Qt::RightButton, Qt::ControlModifier );
 76: zoomer->setMousePattern(QwtEventPattern::MouseSelect3,Qt::RightButton );
 77: time = 0.0;
 78: adPlotTimer = new QTimer();
 79: adPlotTimer->start(100);
 80: connect(adPlotTimer, SIGNAL(timeout()),
 81: this, SLOT(plotAdCurve()));
 82: offset = 0;
 83: }
 84:  
 85: AdPlot::~AdPlot()
 86: {
 87: delete ui;
 88: }
 89:  
 90: void AdPlot::readAdData(QVector<double> &xData, QVector<double> &yData)
 91: {
 92: if(!m_filename.isEmpty())
 93: {
 94: localFile = new QFile(m_filename); //用户端的IP地址+端口号作为文件名 
 95: if (!localFile->open(QFile::ReadOnly ))
 96: {
 97: QMessageBox::warning(0, tr("应用程序"),
 98: tr("无法读取文件 %1:\n%2.")
 99: .arg(m_filename)
 100: .arg(localFile->errorString()));
 101: return;
 102: }
 103: QByteArray adData;
 104: if (!localFile->atEnd())
 105: {
 106: if (offset == 0)
 107: {
 108: adData = localFile->read(26);
 109: qDebug()<<adData;
 110: offset += 26;
 111: adData.resize(0);
 112: return;
 113: }
 114:  
 115: if (localFile->seek(offset))
 116: {
 117:  
 118: adData = localFile->read(32*2);
 119: if (adData.count() == 32*2)
 120: {
 121: for (int count=0; count<32; count++)
 122: {
 123: char lowbits = adData.at(count*2);
 124: char highbits = adData.at(count*2 + 1);
 125: short temp = lowbits+highbits*256;
 126: yData.append(((float)temp)*3300/4096/1000);
 127: xData.append(time);
 128: time += 0.005; //5ms一个数据 
 129: }
 130: offset += 32*2;
 131: }
 132: }
 133: }
 134: }
 135:  
 136: }
 137:  
 138: void AdPlot::plotAdCurve()
 139: {
 140: readAdData(xData,yData);
 141: p_adplot->setSamples(xData,yData);
 142: if (!xData.empty())
 143: {
 144: if (xData.last() >= xMaxScale)
 145: {
 146: xMaxScale *= 2;
 147: ui->qwtPlot->setAxisScale(QwtPlot::xBottom, 0, xMaxScale);
 148: }
 149: }
 150: p_adplot->attach(ui->qwtPlot);
 151: ui->qwtPlot->replot();
 152: adPlotTimer->start(100);
 153:  
 154:  
 155: }
 156:  
 157: void AdPlot::setFileName(QString filename)
 158: {
 159: m_filename = filename;
 160: }
 161:  
 162: void AdPlot::setTitleString(QString title)
 163: {
 164: m_title = title;
 165: ui->qwtPlot->setTitle(m_title);
 166: }
 167:  
 168: void AdPlot::setTimerStop()
 169: {
 170: adPlotTimer->stop();
 171: }

首先:

说一下TimeScaleDraw这个类,它继承了QwtScaleDraw的类,其实就是一个抽象的一个刻度类,具体的函数说明可以参考说明手册.

对了,ui界面里没什么东西,就一个qwtplot的控件image.

 

接着初始化坐标轴:

  1. void setAxisTitle (int axisId, const QString &) 用来设置坐标轴名字,第一个参数是QWT定义的坐标轴ID,即yLeft,yRight,xBottomxTop.
  2. void setAxisScaleDraw (int axisId, QwtScaleDraw *)用来设置坐标轴刻度,第一个参数同上,第二个参数就是我们刚才定义的TimeScaleDraw;
  3. void setAxisScale (int axisId, double min, double max, double step=0)也是设置刻度的,第一个参数同上,第二参数是刻度的最小值,第三个参数是刻度的最大值,最后一个是步长.

 

然后定义一个曲线QwtPlotCurve:

     QwtPlotCurve,它的功能就是输入一系列的X,Y的值,然后绘制出曲线,当然,曲线的color,style那些是可以自己设置的.

 

缩放曲线(PS:这点就体现了QWT的强大之处):

     QwtPlotZoomer,简单的一个类,简单的只个设置就可以缩放曲线,谁用谁知道啊.

 

定时器完成曲线的重绘:

      adPlotTimer = new QTimer();

      adPlotTimer->start(100);

      connect(adPlotTimer, SIGNAL(timeout()), this, SLOT(plotAdCurve()));

      因为所用的AD是400K的,算了一下,大概160ms以下就能满足了.

 

读取AD数据:

     因为服务器接收到的AD数据是保存在文件中的,而且是实时保存(也就是将Client接收的数据保存到文件的同时将此文件中的数据绘制出来).所以设置了一个文件偏移量,而已此文件的前26字节是采集的时间信息,所以跳过.

     又因为用的是AD是12位的,Client采用一个short类型来保存数据,而已每次传输32个AD数据,所以在计算AD数据前要确保文件已经有了32个AD数据,即64字节的数据.

 

绘制AD数据:

     void setSamples (const QVector< double > &xData, const QVector< double > &yData)完成数据的设置.

     此函数重点在于时间轴的拉长:

     if (xData.last() >= xMaxScale)

 {
 xMaxScale *= 2;
 ui->qwtPlot->setAxisScale(QwtPlot::xBottom, 0, xMaxScale);
 }
  

总结:

     qwt的确一个优秀的第三方库,使用也不复杂,而已有详细的文档说明,还有很多例子,不过都是英文的,慢慢看吧.

原创粉丝点击