文章代碼有非常非常之詳細的解析?。。≈T位可放心食用
這個玩意我做了兩個,一個是安卓app,一個是Windows程序。代碼并非全部都是由我從無到有實現(xiàn),只是實現(xiàn)了我想要的功能。多虧了巨人的肩膀,開源萬歲?。?!
我把程序放到GitHub上,需要的可自取。
安卓app:? ?maihelo/Android-WIFI (github.com)
windows程序:maihelo/Windows_tcp (github.com)?
(上面暫且為空,過兩天把代碼整理好就發(fā)上來)
下面我分別對安卓app版本和Windows程序版本進行簡要技術(shù)整理
安卓app:
首先需要對安卓環(huán)境進行配置,這個不同的QT版本對應(yīng)不同的SDK,NDK那些玩意,在這里不做詳細解析。
配置環(huán)境完成以后就可以使用工程了,燒入手機以后呈現(xiàn)出來的效果是這樣的。
?整個工程的框架是:
1、ui頁面繪制
ui頁面有兩個
還有一個就是上面的效果圖
主要是一些PushButton、Lable、CharView控件
2、控件槽函數(shù)的設(shè)計
2.1、第二張圖的“全國大學(xué)生電子設(shè)計大賽上位機”的PushButton
void Widget2::on_MenuBt1_clicked()
{
if(Widget::flag == 0)//通過判斷靜態(tài)成員變量flag來判斷是否創(chuàng)建了Widget
{
Widget *first = new Widget;//創(chuàng)建一個新的 Widget
first->setGeometry(this->geometry());返回當(dāng)前 Widget2 對象的位置和大小信息,用于Widget的呈現(xiàn)
first->show();//將新創(chuàng)建的 Widget 對象顯示在屏幕上
}
this->close();//關(guān)閉Widget2
}
這段代碼的功能就是按下按鈕以后,創(chuàng)建一個Widget并關(guān)閉Widget2,實現(xiàn)簡單的跳轉(zhuǎn)功能。
2.2、按下開啟服務(wù)器按鈕之后的槽函數(shù)
void Widget::on_pushButton_Open_clicked()
{
if(net_flag == 0)//檢查是否連接網(wǎng)絡(luò)
{
if(ui->lineEdit_IP->currentText() != "")//如果IP地址欄不為空
{
QString str = ui->lineEdit_IP->currentText();//收集當(dāng)前IP地址欄的IP地址
if(isIpAddr(str))//判斷IP地址是否有效
{
address.setAddress(str);//設(shè)置收集的IP地址為當(dāng)前IP地址
if(ui->lineEdit_Port->text() != "")//判斷端口欄是否為空
{
port = ui->lineEdit_Port->text().toUInt();//設(shè)置當(dāng)前端口欄的數(shù)字為端口號,并且轉(zhuǎn)為uint16_t格式
net_flag = 1;//網(wǎng)絡(luò)連接標(biāo)志
tcpServer->listen(address,port);//傳入IP地址和端口號開始監(jiān)聽
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(TCPnewconnect_slot()));//當(dāng)連接成功后,將 newConnection 信號連接到 this(即 Widget 對象)的 TCPnewconnect_slot() 槽函數(shù)
ui->label_show->setText("正在連接...");//ui頁面上的label_show發(fā)送字符串"正在連接..."
}
else//與上面對應(yīng),如果端口欄為空
{
QMessageBox::warning(NULL, QStringLiteral("警告"), QStringLiteral("端口號不能為空"),QMessageBox::Ok | QMessageBox::Ok);
}
}
else//與上面對應(yīng),如果IP地址無效
{
QMessageBox::warning(NULL, QStringLiteral("警告"), QStringLiteral("IP不合法"),QMessageBox::Ok | QMessageBox::Ok);//彈窗警告
}
}
else//與上面對應(yīng),如果為IP地址欄為空
{
QMessageBox::warning(NULL, QStringLiteral("警告"), QStringLiteral("IP不能為空"),QMessageBox::Ok | QMessageBox::Ok);//彈窗警告
}
}
}
這個槽函數(shù)的作用是:根據(jù)IP地址欄和端口號欄的輸入信息,判斷是否有效以后,根據(jù)提供的IP地址和端口號開啟監(jiān)聽,并通過connect函數(shù)開啟一個TCP server,如果連接客戶端成功則轉(zhuǎn)到另外一個槽函數(shù)TCPnewconnect_slot(),并且輸出“連接成功”的信息。
TCPnewconnect_slot():
void Widget::TCPnewconnect_slot()
{
tcpSocket = tcpServer->nextPendingConnection();//獲取新的客戶端連接,并將返回的 QTcpSocket 對象賦值給 tcpSocket 成員變量
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(TCPreadyread_slot()));//當(dāng)有TcpSocket的readyRead()信號,也就是客戶端有數(shù)據(jù)發(fā)送上來的時候,連接當(dāng)前Wiget的槽函數(shù)TCPreadyread_slot()
ui->label_show->setText("網(wǎng)絡(luò)已連接");//標(biāo)簽顯示
}
這個槽函數(shù)收到客戶端發(fā)送的數(shù)據(jù)以后,再跳轉(zhuǎn)到TCPreadyread_slot()槽函數(shù),這個槽函數(shù)是數(shù)據(jù)處理這塊的,我到第四大點的時候再詳細講。
2.3、按下關(guān)閉服務(wù)器按鈕以后的槽函數(shù)
void Widget::on_pushButton_Close_clicked()
{
if(net_flag == 1)//判斷網(wǎng)絡(luò)是否連接,如果是,往下
{
tcpSocket->close();//關(guān)閉tcpSocket,斷開與當(dāng)前客戶端的連接
tcpServer->close();//關(guān)閉tcpServer,停止監(jiān)聽新的客戶端連接
disconnect(tcpServer,SIGNAL(newConnection()),this,SLOT(TCPnewconnect_slot()));//將tcpServer的newConnection()信號與槽函數(shù)TCPnewconnect_slot()斷開連接
disconnect(tcpSocket,SIGNAL(readyRead()),this,SLOT(TCPreadyread_slot()));//將tcpSocket的readyRead()信號與槽函數(shù)TCPreadyread_slot()斷開連接
net_flag = 0;//將flag置為0,表示網(wǎng)絡(luò)斷開
}
ui->label_show->setText("連接已關(guān)閉");//輸出標(biāo)簽信息
}
這個槽函數(shù)是斷開對客戶端的監(jiān)聽和連接,斷開各種信號與相應(yīng)槽函數(shù)的連接,關(guān)閉服務(wù)器。
3.4、按下掃描按鍵以后的槽函數(shù)
void Widget::on_Scan_clicked()
{
ui->lineEdit_IP->clear();//IP地址欄全部清空
QList<QString> strIpAddress;
QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();//獲取主機所有IP地址并存放在ipAddressesList這個列表里
// 獲取第一個本主機的IPv4地址
int nListSize = ipAddressesList.size();
for (int i = 0; i < nListSize; ++i)
{
if (ipAddressesList.at(i) != QHostAddress::LocalHost &&ipAddressesList.at(i).toIPv4Address())//排除主機IP地址,并且保證IP地址是IPV4格式
{
strIpAddress.append(ipAddressesList.at(i).toString());//將滿足條件的IP地址放入strIpAddress里面
// break;
}
}
// 如果沒有找到,則以本地IP地址為IP
if (strIpAddress.isEmpty())strIpAddress.append(QHostAddress(QHostAddress::LocalHost).toString());
ui->lineEdit_IP->addItems(strIpAddress);//把IP地址顯示到IP地址欄
}
這個槽函數(shù)是用于查找設(shè)備當(dāng)中的IP地址,并且將它顯示到IP地址欄。
3、繪圖板塊的設(shè)計
//設(shè)置坐標(biāo)軸
chart2->addSeries(line2);// 添加數(shù)據(jù)線 line2 到圖表 chart2 中
chart2->setTheme(QChart::ChartThemeQt);//設(shè)置圖表 chart2 的主題為 Qt 默認(rèn)的主題
line2->setName("時域波形");//數(shù)據(jù)線名稱
line2->setColor(Qt::red);//數(shù)據(jù)線的顏色
//創(chuàng)建兩個 QValueAxis 對象 axisX2 和 axisY2,用于設(shè)置 X 軸和 Y 軸的顯示樣式和屬性
QValueAxis *axisX2 = new QValueAxis;
QValueAxis *axisY2 = new QValueAxis;
axisX2->setLabelFormat("%.0f");//顯示格式為 "%.0f",即只顯示整數(shù)部分
axisX2->setLabelsAngle(45);//標(biāo)簽角度為 45 度(x軸或者y軸的刻度標(biāo)簽)
axisX2->setLabelsColor(Qt::blue);//標(biāo)簽顏色
axisY2->setLabelFormat("%.0f");
axisY2->setLabelsAngle(45);
axisY2->setLabelsColor(Qt::blue);
axisX2->setRange(0,200);//x軸的范圍
axisY2->setRange(0,255);//y軸的范圍
axisX2->setGridLineVisible(true);//設(shè)置網(wǎng)格線是否可見
axisX2->setGridLineColor(Qt::black);//網(wǎng)格線的顏色
axisX2->setMinorTickCount(1);//精度設(shè)置為1
axisX2->setMinorGridLineColor(Qt::black);//設(shè)置小網(wǎng)格為黑色
axisX2->setMinorGridLineVisible(true);//設(shè)置小網(wǎng)格可見
axisX2->setLabelsVisible(false); //設(shè)置刻度是否顯示
axisY2->setGridLineVisible(true);
axisY2->setGridLineColor(Qt::black);
axisY2->setMinorTickCount(1);
axisY2->setMinorGridLineColor(Qt::black);
axisY2->setMinorGridLineVisible(true);
axisY2->setLabelsVisible(false); //設(shè)置刻度是否顯示
//將 X 軸和 Y 軸添加到圖表 chart2 中
chart2->addAxis(axisX2,Qt::AlignBottom);
chart2->addAxis(axisY2,Qt::AlignLeft);
chart2->layout()->setContentsMargins(0, 0, 0, 0);//設(shè)置外邊界全部為0
chart2->setMargins(QMargins(0, 0, 0, 0));//設(shè)置內(nèi)邊界全部為0
chart2->setBackgroundRoundness(0);//設(shè)置背景區(qū)域無圓角
line2->attachAxis(axisX2);//將數(shù)據(jù)線 line2 附加到 X 軸 axisX2
line2->attachAxis(axisY2);//將數(shù)據(jù)線 line2 附加到 Y 軸 axisY2
ui->widget_2->setChart(chart2);//顯示圖表 chart2
4、數(shù)據(jù)處理板塊設(shè)計
根據(jù)第二大點所遺留下來的問題,TCPnewconnect_slot()槽函數(shù)收到客戶端發(fā)送的數(shù)據(jù)以后,再跳轉(zhuǎn)到TCPreadyread_slot()槽函數(shù)。數(shù)據(jù)處理就在TCPreadyread_slot()里面進行。
extern uint8_t cmd_buffer[A_CMD_MAX_SIZE];
static uint16_t size = 0;
void Widget::TCPreadyread_slot()
{
uint16_t size = 0;
//定義兩個數(shù)組
QByteArray temp1;
QByteArray temp2;
int iterationCount = 0; // 用于計數(shù)循環(huán)迭代次數(shù)
do {
temp2 = temp1;//先將temp1中的數(shù)傳遞給temp2
temp1 = tcpSocket->readAll();//temp1讀客戶端發(fā)送的數(shù)據(jù)
iterationCount++;//次數(shù)加一
qDebug() << "Iteration:" << iterationCount;打印次數(shù)
qDebug() << "Data read in this iteration:" << temp2;//打印temp2里面的值
} while (!temp1.isEmpty());//當(dāng)temp1里面沒有數(shù)據(jù)時,退出循環(huán)
qDebug() << "temp2 len is:" << temp2.length();//打印數(shù)據(jù)的長度
// 將QByteArray轉(zhuǎn)換為QString
QString dataStr = QString::fromUtf8(temp2);//把數(shù)組里面的數(shù)據(jù)轉(zhuǎn)化為字符串
// 使用split函數(shù)按逗號拆分字符串,得到QStringList
QStringList strList = dataStr.split(',');
// 創(chuàng)建一個整型數(shù)組,用于存儲拆分后的數(shù)字
QList<int> dataArray;
// 遍歷QStringList,將每個字符串轉(zhuǎn)換為整數(shù)并存儲到dataArray中
//注意這里和C語言的用法不太一樣,它的初始化部分和執(zhí)行條件以及迭代部分會自動檢測更新
for (const QString& str : strList) {
bool ok;//布爾變量??,用于存儲ture和false兩個值
int number = str.toInt(&ok);//如果成功,則布爾變量返回ture,并且把值存放在number中,否則布爾變量為false
if (ok) {//如果布爾變量為ture
dataArray.append(number);//將number里面的值放入dataArray數(shù)組里面
}
}
// 輸出拆分后的整數(shù)數(shù)組
for (int number : dataArray) {//輸出dataArray里面的數(shù)
qDebug() << number;
}
qDebug() << "dataArray len is:" << dataArray.length();//長度
for(int i = 0;i<dataArray.length();i++)
{
A_queue_push(dataArray[i]); //添加指令里面的數(shù)據(jù)
size = A_queue_find_cmd(cmd_buffer,A_CMD_MAX_SIZE); //從緩沖區(qū)中獲取一條指令 ,這里會有個返回值size,如果size=0,代表沒有一條完整的指令,自然葉無法進入指令處理函數(shù)里面去(一條完整的指令包括幀頭和幀尾以及數(shù)據(jù)體)
if(size>0) //接收到指令
{
qDebug() << "Contents of cmd_buffer:";
for (uint16_t i = 0; i < size; i++) {
qDebug() << static_cast<int>(cmd_buffer[i]);
}
qDebug() << "size:" << size;
A_ProcessMessage(cmd_buffer, size,ui); //指令處理
}
}
}
經(jīng)過上面的分析我們知道,數(shù)據(jù)處理主要是對指令的處理。而指令處理主要包括以下三個函數(shù)
A_queue_push(dataArray[i]); A_queue_find_cmd(cmd_buffer,A_CMD_MAX_SIZE); A_ProcessMessage(cmd_buffer, size,ui);
下面逐個來分析:
A_queue_push(dataArray[i]);
#define A_CMD_HEAD 0XEE //幀頭
#define A_CMD_TAIL 0xFFFCFFFF //幀尾(這里需要注意以下,不是一個數(shù)喔,不然數(shù)據(jù)溢出沒法判斷是不是幀尾咯)
typedef struct A_QUEUE
{
uint16_t _head; //隊列頭
uint16_t _tail; //隊列尾
uint8_t _data[A_QUEUE_MAX_SIZE]; //隊列數(shù)據(jù)緩存區(qū)
} A_QUEUE;
static A_QUEUE A_que = {0,0,0}; //指令隊列
static uint32_t A_cmd_state = 0; //隊列幀尾檢測狀態(tài)
static uint16_t A_cmd_pos = 0; //當(dāng)前指令指針位置
/*!
* \brief 清空指令數(shù)據(jù)
*/
void A_queue_reset()
{
A_que._head = A_que._tail = 0;
A_cmd_pos = A_cmd_state = 0;
}
/*!
* \brief 添加指令數(shù)據(jù)
* \detial 串口接收的數(shù)據(jù),通過此函數(shù)放入指令隊列
* \param _data 指令數(shù)據(jù)
*/
void A_queue_push(uint32_t _data)
{
uint16_t pos = (A_que._head+1)%A_QUEUE_MAX_SIZE; //每來一個數(shù)據(jù)隊列頭就會+1
if(pos!=A_que._tail) //非滿狀態(tài)
{
A_que._data[A_que._head] = _data; //數(shù)據(jù)依次進入依次存放在隊列里面
A_que._head = pos; //隊列頭每來一個數(shù)據(jù)+1的基礎(chǔ)
// 添加調(diào)試信息
qDebug() << "A_queue_push: Data added to queue:" << static_cast<int>(_data);
qDebug() << "A_queue_push: Queue head:" << A_que._head << "Queue tail:" << A_que._tail;
}
}
A_queue_push(dataArray[i]);的作用是在dataArray數(shù)組遍歷的條件下,將數(shù)組里面的數(shù)據(jù)依次放入隊列中。
A_queue_find_cmd(cmd_buffer,A_CMD_MAX_SIZE);
//從隊列中取一個數(shù)據(jù)
static void queue_pop(uint8_t* _data)
{
if(A_que._tail!=A_que._head) //非空狀態(tài)
{
*_data = A_que._data[A_que._tail];
A_que._tail = (A_que._tail+1)%A_QUEUE_MAX_SIZE;
}
}
//獲取隊列中有效數(shù)據(jù)個數(shù)
uint16_t A_queue_size()
{
return ((A_que._head+A_QUEUE_MAX_SIZE-A_que._tail)%A_QUEUE_MAX_SIZE);
}
/*!
* \brief 從指令隊列中取出一條完整的指令
* \param cmd 指令接收緩存區(qū)
* \param buf_len 指令接收緩存區(qū)大小
* \return 指令長度,0表示隊列中無完整指令
*/
uint16_t A_queue_find_cmd(uint8_t *buffer,uint16_t buf_len)//qdata uint8_t qsize uint16_t
{
uint16_t cmd_size = 0;
uint8_t _data = 0;
while(A_queue_size()>0)//當(dāng)隊列的長度(有效數(shù)字個數(shù))大于0時往下
{
//取一個數(shù)據(jù)
queue_pop(&_data);
if(A_cmd_pos==0&&_data!=A_CMD_HEAD) //指令第一個字節(jié)必須是幀頭,否則跳過
{
qDebug() << "Skipping data:" << static_cast<int>(_data);
continue;
}
// 輸出當(dāng)前取出的數(shù)據(jù)和指令指針位置
qDebug() << "A_queue_find_cmd: Current data: " << _data << " A_cmd_pos: " << A_cmd_pos;
if(A_cmd_pos<buf_len) //防止緩沖區(qū)溢出,這里傳入的形參是A_CMD_MAX_SIZE(一條指令最大的大?。?,也就是2048
buffer[A_cmd_pos++] = _data;//每進入一次while循環(huán),數(shù)據(jù)會依次更新到buffer里面
A_cmd_state = ((A_cmd_state<<8)|_data); //拼接最后4個字節(jié),組成一個32位整數(shù),如果不是最后四個字節(jié),那自然無法進入下面的if語句
qDebug() <<" A_cmd_state: " << A_cmd_state;
//最后4個字節(jié)與幀尾匹配,得到完整幀
if(A_cmd_state==A_CMD_TAIL)
{
cmd_size = A_cmd_pos; //指令字節(jié)長度
A_cmd_state = 0; //重新檢測幀尾巴
A_cmd_pos = 0; //復(fù)位指令指針
#if(CRC16_ENABLE)
//去掉指令頭尾EE,尾FFFCFFFF共計5個字節(jié),只計算數(shù)據(jù)部分CRC
if(!CheckCRC16(buffer+1,cmd_size-5)) //CRC校驗
return 0;
cmd_size -= 2; //去掉CRC16(2字節(jié))
#endif
qDebug() << "Found complete command! Command size:" << cmd_size;
return cmd_size; //返回指令的大小
}
}
return 0; //沒有形成完整的一幀
}
這個函數(shù)是尋找一條完整的指令,如果尋找成功則返回指令的字節(jié)大小。解析里面有說一條完整的指令需要幀頭和幀尾,如果不滿足則無法獲取cmd_size的值,也就無法進入數(shù)據(jù)處理函數(shù)A_ProcessMessage(cmd_buffer, size,ui);所以發(fā)送指令的時候一定要按照標(biāo)準(zhǔn)的格式來發(fā)送。我的數(shù)據(jù)格式如下:
int touAndCmd[] = {0XEE,0x03,0,1};//幀頭以及以下id號,這篇代碼下面就講
int dataBuffer[] = {10,20,30,40,50,60,70,80,90,100,110,100,90,80,70,60,50,40,30,20,10};
int zhenwei[] = {0xFF,0xFC,0xFF,0xFF};//真尾,別傻傻的0xFFFCFFFF了(手動狗頭)
int len = sizeof(touAndCmd)/sizeof(touAndCmd[0]);
int len1 = sizeof(dataBuffer)/sizeof(dataBuffer[0]);
int len2 = sizeof(zhenwei)/sizeof(zhenwei[0]);
//下面自己看了,就是發(fā)送一串?dāng)?shù)據(jù),然后以逗號隔開就完了
for(int i = 0;i<len;i++){
printf("%d,",touAndCmd[i]);
}
for(int k = 0;k<5;k++){
for(int i = 0;i<len1;i++){
printf("%d,",dataBuffer[i]);
}
}
for(int m = 0;m<len2;m++){
if(m == (len2-1)){
printf("%d",zhenwei[m]);
}else{
printf("%d,",zhenwei[m]);
}
}
好了,最后一步:
A_ProcessMessage(cmd_buffer, size,ui);怎么處理我們發(fā)送上來的數(shù)據(jù)?
#include "qglobal.h"
#include "cmd_queue.h"
#include "process_fun.h"
#include "widget.h"
uint8_t cmd_buffer[A_CMD_MAX_SIZE];
void A_ProcessMessage(/*A_PCTRL_MSG */uint8_t msg[2048], uint16_t size,Ui::Widget *dis)
{
/*這是cmd_type的宏定義,其實用不上這么多
enum A_CtrlType
{
A_kCtrlUnknown=0x00,
A_kCtrlButton=0x01, //按鈕
A_kCtrlText = 0x02, //文本
A_kCtrlGraph = 0x03, //曲線圖控件
A_kCtrlTable = 0x04, //表格控件
A_kCtrlMenu = 0x05, //菜單控件
A_kCtrlSelector = 0x06, //選擇控件
};
*/
uint8_t cmd_type = msg[1]; //命令類型
uint8_t screen_id = msg[2]; //畫面ID
uint8_t control_id = msg[3]; //控件ID
//調(diào)試信息打印
qDebug() << "cmd_type:"<<msg[1];
qDebug() << "screen_id:"<<screen_id;
qDebug() << "control_id:"<<control_id;
switch(cmd_type)
{
case A_kCtrlButton: //按鈕控件
A_NotifyButton(screen_id,control_id);
break;
case A_kCtrlText: //文本控件
// A_NotifyText(screen_id,control_id,msg->param,dis);
A_NotifyText(screen_id,control_id,&msg[4],dis);
break;
case A_kCtrlGraph:
// A_NotifyGraph(screen_id,control_id,len,&msg->param[2]); //畫圖控件
A_NotifyGraph(screen_id, control_id, size - 8, &msg[4]); // 注意減去幀頭、幀尾和控件ID的長度
default:
break;
}
}
void A_NotifyText(uint16_t screen_id, uint16_t control_id, uint8_t *str,Ui::Widget *dis)
{
if(screen_id == 0)//判斷輸入的第二個數(shù)是否為0,如果是,就可以為那些基波啥啥啥的賦值了
{
if(control_id == 3)
{
Widget::updatedata3(str,1,dis);
}
else if(control_id == 4)
{
Widget::updatedata3(str,2,dis);
}
else if(control_id == 5)
{
Widget::updatedata3(str,3,dis);
}
else if(control_id == 6)
{
Widget::updatedata3(str,4,dis);
}
else if(control_id == 7)
{
Widget::updatedata3(str,5,dis);
}
else if(control_id == 8)
{
Widget::updatedata3(str,6,dis);
}
}
}
void A_NotifyButton(uint16_t screen_id, uint16_t control_id)
{
if(screen_id == 0)
{
if(control_id == 10)
{
}
else if(control_id == 3)
{
}
}
}
void A_NotifyGraph(uint16_t screen_id, uint16_t control_id, uint16_t length,uint8_t *str)
{
int i = 0;
float temp = 0;
if(screen_id == 0)
{
// if(control_id == 0)//這里因為我只用了一個畫布,所以這里就不要啦
// {
// qDebug()<<length<<endl;
// qDebug()<<str;
// while(i<length)
// {
// temp = str[i++];
// Widget::updatedata(temp);
// }
// }
// else
if(control_id == 1)
{
while(i<length)
{
temp = str[i++];
Widget::updatedata2(temp);//Widget中不斷進行updatedata2這個函數(shù)
}
}
}
}
好的,到這里所有代碼基本分析完畢了,由上面我們知道updatedata2是畫布的updatedata3是各個空白框的。下面最后來看一下這兩個函數(shù):
void Widget::updatedata2(float input)
{
static int i2=0;//先整個作用在這個函數(shù)里邊的靜態(tài)變量
static QVector<QPointF> data0=line2->pointsVector();//QVector<QPointF> 類型的容器,用于存儲圖表的數(shù)據(jù)點
//控制數(shù)值在0-255之間
if(input<0)input = 0;
if(input>255)input = 255;
if(i2<1024)
{
data0.append(QPointF(i2,input));//在 data0 中添加一個新的數(shù)據(jù)點,x 坐標(biāo)為 i2,y 坐標(biāo)為 input
i2++;
line2->replace(data0);//將更新后的數(shù)據(jù)點更新到 line2 圖表中
}
else//如果數(shù)據(jù)量超過1024
{
QVector<QPointF> data2;//再來一個容器
for(int j = 0;j<1023;j++)
{
data2.append(QPointF(j,data0.at(j+1).y()));//將 data0 中的數(shù)據(jù)點從索引 1 開始拷貝到 data2,相當(dāng)于刪除data0中的數(shù)據(jù)
}
data2.append(QPointF(1023,input));//data2添加新的數(shù)據(jù)點,x 坐標(biāo)為 1023,y 坐標(biāo)為 input
data0 = data2;//更新data0中的數(shù)據(jù)
line2->replace(data0);///將更新后的數(shù)據(jù)點更新到 line2 圖表中
}
}
updatedata3:文章來源:http://www.zghlxwxcb.cn/news/detail-611322.html
void Widget::updatedata3(uint8_t* input,int index,Ui::Widget *dis)
{
QByteArray qstr;//定義一個數(shù)組
int i = 0;
for(i;i<sizeof(input);i++)//遍歷input里面的數(shù)據(jù)
{
qstr.append(input[i]);//qstr存放input里面的數(shù)據(jù)
}
QString str = QString(qstr);//將 QByteArray 類型的 qstr 轉(zhuǎn)換為 QString 類型的 str
qDebug()<<str;
switch(index)//index不同寫入不同的空白框
{
case 1:
{
dis->lineEdit->setText(str);
break;
}
case 2:
{
dis->lineEdit_2->setText(str);
break;
}
case 3:
{
dis->lineEdit_3->setText(str);
break;
}
case 4:
{
dis->lineEdit_4->setText(str);
break;
}
case 5:
{
dis->lineEdit_5->setText(str);
break;
}
case 6:
{
dis->lineEdit_6->setText(str+"%");
break;
}
}
}
Windows程序和這個大同小異,就不具體介紹了,看懂上面這些Windows程序肯定莫得問題。文章來源地址http://www.zghlxwxcb.cn/news/detail-611322.html
到了這里,關(guān)于QT基于TCP協(xié)議實現(xiàn)數(shù)據(jù)傳輸以及波形繪制——安卓APP及Windows程序雙版本的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!