关于QUdpSocket和Qwt动态曲线的小例子
最近项目中遇到的一个需求是关于用udp接收数据来显示一个动态曲线,觉得以后可能还会遇到于是写一个小例子记录一下。废话不多说直接贴代码。
首先是数据发送端:
新建一个Qt Widgets Application,选择Qwidget,其中工程文件如下:
其中主要是QudpSocket的使用其他没什么可说的。
#-------------------------------------------------
#
# Project created by QtCreator 2018-06-07T19:21:13
#
#-------------------------------------------------
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = QUdpServer
TEMPLATE = app
SOURCES += main.cpp\
widgetserver.cpp
HEADERS += widgetserver.h \
# thetestdata.h
FORMS += widgetserver.ui
头文件如下:
#ifndef WIDGETSERVER_H
#define WIDGETSERVER_H
#include <QWidget>
#include <QUdpSocket>
#include <QDebug>
namespace Ui {
class WidgetServer;
}
class WidgetServer : public QWidget
{
Q_OBJECT
public:
explicit WidgetServer(QWidget *parent = 0);
~WidgetServer();
private slots:
void on_pushButton_send_clicked();
void time_out_Slot();
private:
void initSorket();
private:
Ui::WidgetServer *ui;
QUdpSocket* sender;
QTimer* timer;
};
#endif // WIDGETSERVER_H
源文件:
#include "widgetserver.h"
#include "ui_widgetserver.h"
#include "thetestdata.h"
#include <QDebug>
#include <QTime>
#include <QTimer>
WidgetServer::WidgetServer(QWidget *parent) :
QWidget(parent),
ui(new Ui::WidgetServer)
{
ui->setupUi(this);
timer = new QTimer(this);
timer->start(1000);
initSorket();
connect(timer, SIGNAL(timeout()), this, SLOT(time_out_Slot()));
}
WidgetServer::~WidgetServer()
{
delete ui;
}
//初始化QUdpSocket
void WidgetServer::initSorket()
{
sender = new QUdpSocket(this);
sender->bind(QHostAddress::Broadcast, 7755);
}
void WidgetServer::on_pushButton_send_clicked()
{
}
//时间槽函数 并对数据进行赋值发送
void WidgetServer::time_out_Slot()
{
Massege_Data msg;
int msg_length = sizeof(Massege_Data);
qDebug()<<msg_length;
memset(&msg,0,sizeof(Massege_Data));
msg.massege_header.massege_header = 1001;
msg.massege_header.msg_num = 1;
msg.test_data1 = 1;
msg.test_data2 = 2;
msg.massege_header.massege_length_uh = sizeof(Massege_Data);
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
for(int i=0 ; i< 100;++i)
{
msg.the_y[i]= qrand()%90;
}
sender->writeDatagram((char*)&msg,sizeof(Massege_Data),QHostAddress::LocalHost,7755);
// qreal xy = sender->write((char*)&msg,sizeof(Massege_Data));
// if(xy==-1)
// {
// qDebug()<<sender->errorString();
// }
}
其中的结构体是单独的一个文件thetestdata.h放在和发送端的头文件和源文件相同的目录中:
#ifndef THETESTDATA_H
#define THETESTDATA_H
#pragma pack(1)
#ifndef _MASSEGE_HEADER
#define _MASSEGE_HEADER
typedef struct MassegeHeader{
unsigned short int massege_header;//消息头
unsigned short int massege_length_uh;//消息长度
unsigned short int msg_num;//包数号
unsigned short int msg_num_all;//总包数
unsigned int time_e;//时间戳
unsigned char spare_uc[9];//消息源
unsigned char bak[3];
}MassegeHeader;
#endif
#ifndef _MAGGEGE_DATA
#define _MAGGEGE_DATA
typedef struct Massege_Data{
MassegeHeader massege_header;
unsigned short int test_data1;
unsigned short int test_data2;
unsigned short int the_y[100];
}Massege_Data;
#endif
#pragma pack()
#endif // THETESTDATA_H
接下来是接收端也是新建Qt Widgets Application,选择Qwidget,要稍微复杂一点的就是重写了Qwt:
其界面如图:
其工程文件如下:
#-------------------------------------------------
#
# Project created by QtCreator 2018-06-09T20:57:32
#
#-------------------------------------------------
QT += core gui network
CONFIG += qwt
DEFINES += QT_DLL QWT_DLL
LIBS += -L"D:\build-qwt-Desktop_Qt_5_6_3_MSVC2013_64bit-Debug\lib" -lqwtd
LIBS += -L"D:\build-qwt-Desktop_Qt_5_6_3_MSVC2013_64bit-Debug\lib" -lqwt
INCLUDEPATH += F:\Qt\Qt5.6.3\5.6.3\msvc2013_64\include\QWT
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = UdpClient
TEMPLATE = app
SOURCES += main.cpp\
clientwidget.cpp
HEADERS += clientwidget.h
FORMS += clientwidget.ui
头文件如下:
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#include <QWidget>
#include <qmath.h>
#include <QVector>
#include <qwt_plot.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_magnifier.h>
#include <qwt_plot_panner.h>
#include <qwt_legend.h>
#include <qwt_point_data.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_picker.h>
#include <qwt_picker.h>
#include <QColor>
#include <QDebug>
#include <QUdpSocket>
#include <QPen>
#include <QTimer>
namespace Ui {
class ClientWidget;
}
class ClientWidget : public QWidget
{
Q_OBJECT
public:
explicit ClientWidget(QWidget *parent = 0);
~ClientWidget();
//设置画布标题
void setPlotTitle(const QString &strTitle);
//重绘
void reDraw();
//设置x轴,y轴信息
void setAxisTitles(QwtPlot::Axis asixId,const QString &strText);
//设置x,y的值
void setAxisRange(QwtPlot::Axis asixId,const double dStart,const double dEnd,const double dIndex=0.0);
//创建网格
QwtPlotGrid* createGrid();
//获取网格
QwtPlotGrid* getGrid();
//设置是否显示
void setGridIsShow(QwtPlot::Axis asixId,bool show);
//设置网格类型和颜色
void setGridColor(QColor color,qreal qrlinewidth,Qt::PenStyle ePenStyle);
//创建曲线
QwtPlotCurve* createCurve();
//设置曲线是否显示
void setCurveIsShow(QwtPlotCurve* pCurve,bool show);
//删除曲线
void delCurve(QwtPlotCurve* pCurve);
//设置曲线数据和颜色
void setCurveData(QwtPlotCurve* pCurve, QwtPointArrayData * const data,QPen pen);
void addItem(int ixPos,int iYPos,const QwtText &qwtText);
void delItem(QwtPlotItem *plotItem);
void setItemPos(QwtPlotItem *plotItem,int ixPos,int iyPos);
void setItemIsShow(QwtPlotItem *plotItem,bool show);
void setTipMsg(QPoint pos,QString strText);
protected:
void resizeEvent(QResizeEvent* re);
private slots:
void on_pushButton_clicked();
void readPendingDatagrams();
void time_out_Slot();
private:
Ui::ClientWidget *ui;
QList<QwtPlotCurve*> m_listCurve;
QList<QwtPlotItem*> m_listItem;
QwtPlotGrid *m_plotGrid;
QwtPlot* m_plot;
QwtPlotPicker * m_picker;
double m_dXStart,m_dYStart,m_dXEnd,m_dYEnd;
QUdpSocket* recvUdpSocket;
QwtPlotCurve* testCurve;
QwtPlotCurve* Msg_Udp_Curve;
QTimer *timer;
};
#endif // CLIENTWIDGET_H
源文件如下:
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QFont>
#include <QPolygonF>
#include <QResizeEvent>
#include "thetestdata.h"
#include <QTime>
ClientWidget::ClientWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidget)
{
ui->setupUi(this);
m_plot = NULL;
m_plot = ui->plot;
m_plotGrid = NULL;
createGrid();
m_listCurve.clear();
m_listItem.clear();
m_picker = new QwtPlotPicker(QwtPlot::xBottom,QwtPlot::yLeft,
QwtPicker::PolygonRubberBand,
QwtPicker::AlwaysOn,m_plot->canvas());
m_picker->setRubberBandPen(QColor(Qt::green));
m_picker->setRubberBand(QwtPicker::CrossRubberBand);
m_picker->setTrackerPen(QColor(Qt::black));
(void) new QwtPlotMagnifier(m_plot->canvas());
(void) new QwtPlotPanner( m_plot->canvas() );
recvUdpSocket = new QUdpSocket(this);
recvUdpSocket->bind(QHostAddress::LocalHost, 7755);
connect(recvUdpSocket, SIGNAL(readyRead()),
this, SLOT(readPendingDatagrams()));
timer = new QTimer(this);
timer->start(1000);
//connect(timer, SIGNAL(timeout()), this, SLOT(time_out_Slot()));
testCurve = NULL;
testCurve = createCurve();
Msg_Udp_Curve = NULL;
Msg_Udp_Curve = createCurve();
}
ClientWidget::~ClientWidget()
{
delete ui;
}
void ClientWidget::setPlotTitle(const QString &strTitle)
{
QwtText qwtText = QwtText(strTitle);
qwtText.setFont(QFont("Bitstream Charter",12,50,false));
m_plot->setTitle(qwtText);
}
void ClientWidget::reDraw()
{
m_plot->replot();
// m_plot->detachItems();
}
void ClientWidget::setAxisTitles(QwtPlot::Axis asixId, const QString &strText)
{
QwtText qwtText = QwtText(strText);
qwtText.setFont(QFont("Bitstream Charter",9,50,false));
m_plot->setAxisTitle(asixId,qwtText);
}
void ClientWidget::setAxisRange(QwtPlot::Axis asixId, const double dStart, const double dEnd, const double dIndex)
{
m_plot->setAxisScale(asixId,dStart,dEnd,dIndex);
if(asixId==QwtPlot::xBottom)
{
m_dXStart = dStart;
m_dXEnd = dEnd;
}
else if (asixId==QwtPlot::yLeft)
{
m_dYStart = dStart;
m_dYEnd = dEnd;
}
}
QwtPlotGrid *ClientWidget::createGrid()
{
if(m_plotGrid != NULL) return m_plotGrid;
m_plotGrid = new QwtPlotGrid;
setGridColor(Qt::gray,0.0,Qt::DotLine);
m_plotGrid->attach(m_plot);
}
QwtPlotGrid *ClientWidget::getGrid()
{
return m_plotGrid;
}
void ClientWidget::setGridIsShow(QwtPlot::Axis asixId, bool show)
{
if(m_plotGrid == NULL) return;
if(asixId == QwtPlot::xBottom)
m_plotGrid->enableX(show);
else if(asixId == QwtPlot::yLeft)
m_plotGrid->enableY(show);
}
void ClientWidget::setGridColor(QColor color, qreal qrlinewidth, Qt::PenStyle ePenStyle)
{
if(m_plotGrid == NULL) return;
m_plotGrid->setPen(QPen(color,qrlinewidth,ePenStyle));
}
QwtPlotCurve *ClientWidget::createCurve()
{
QwtPlotCurve* pCurve = new QwtPlotCurve();
pCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
m_listCurve.append(pCurve);
pCurve->attach(m_plot);
return pCurve;
}
void ClientWidget::setCurveIsShow(QwtPlotCurve *pCurve, bool show)
{
if(show)
{
if(!m_listCurve.contains(pCurve))
m_listCurve.append(pCurve);
pCurve->attach(m_plot);
}
else
{
pCurve->detach();
}
}
void ClientWidget::delCurve(QwtPlotCurve *pCurve)
{
if(m_listCurve.contains(pCurve)) return;
m_listCurve.removeOne(pCurve);
pCurve->detach();
delete pCurve;
pCurve = NULL;
}
void ClientWidget::setCurveData(QwtPlotCurve *pCurve,QwtPointArrayData * const data, QPen pen)
{
if(pCurve != NULL)
pCurve->setData(data);
pCurve->setPen(pen);
}
void ClientWidget::addItem(int ixPos, int iYPos, const QwtText &qwtText)
{
}
void ClientWidget::delItem(QwtPlotItem *plotItem)
{
}
void ClientWidget::setItemPos(QwtPlotItem *plotItem, int ixPos, int iyPos)
{
}
void ClientWidget::setItemIsShow(QwtPlotItem *plotItem, bool show)
{
}
void ClientWidget::setTipMsg(QPoint pos, QString strText)
{
}
void ClientWidget::resizeEvent(QResizeEvent *re)
{
int w = re->size().width();
QWidget::resizeEvent(re);
}
void ClientWidget::on_pushButton_clicked()
{
timer->stop();
}
void ClientWidget::readPendingDatagrams()
{
Massege_Data msg;
memset(&msg,0,sizeof(Massege_Data));
while (recvUdpSocket->hasPendingDatagrams()) {
QByteArray datagram;
QHostAddress sender = QHostAddress::LocalHost;
quint16 senderPort = 7755;
datagram.resize(recvUdpSocket->pendingDatagramSize());
recvUdpSocket->readDatagram((char*)&msg, sizeof(Massege_Data),
&sender,&senderPort);
}
QVector<double> xs;
QVector<double> ys;
for (int i=0;i<100;++i)
{
ys.append(msg.the_y[i]);
xs.append(i);
}
//构造曲线数据
QwtPointArrayData * const data = new QwtPointArrayData(xs, ys);
//
setAxisRange(QwtPlot::xBottom,0,100);
setAxisRange(QwtPlot::yLeft,0,100);
setAxisTitles(QwtPlot::xBottom,"x__");
setAxisTitles(QwtPlot::yLeft,QString("y__"));
setCurveData(Msg_Udp_Curve,data,QPen(Qt::blue));
reDraw();
}
void ClientWidget::time_out_Slot()
{
if(testCurve != NULL)
delCurve(testCurve);
Massege_Data msg_test;
int msg_length = sizeof(Massege_Data);
qDebug()<<msg_length;
memset(&msg_test,0,sizeof(Massege_Data));
msg_test.massege_header.massege_header = 1001;
msg_test.massege_header.msg_num = 1;
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
for(int i=0 ; i< 100;++i)
{
msg_test.the_y[i] = qrand()%90;
}
QVector<double> xs;
QVector<double> ys;
for (int i=0;i<100;++i)
{
ys.append(msg_test.the_y[i]);
xs.append(i);
}
//构造曲线数据
QwtPointArrayData * const data = new QwtPointArrayData(xs, ys);
setAxisRange(QwtPlot::xBottom,0,100);
setAxisRange(QwtPlot::yLeft,0,100);
setCurveData(testCurve,data,QPen(Qt::red));
reDraw();
}
其中结构体文件和发送端一样也是放在与接收端的源文件一个目录。
其显示的效果如下: