




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第Qt中PaintEvent繪制實(shí)時(shí)波形圖的實(shí)現(xiàn)示例目錄繪制思路1:接收硬件傳入的數(shù)據(jù)2:定時(shí)器動(dòng)態(tài)刷新頁(yè)面3:真實(shí)數(shù)據(jù)處理第一步:每進(jìn)行一次數(shù)據(jù)更新,都需要剔除超時(shí)顯示數(shù)據(jù)。第二步:篩查有效數(shù)據(jù),并記錄4:圖形繪制上一篇文章講述了如何使用控件進(jìn)行波形圖繪制,雖然很方便,但是也有一些無(wú)法避免的問(wèn)題,比如說(shuō):動(dòng)態(tài)繪制圖形時(shí),想要流暢的進(jìn)行波動(dòng),就必須按照特定的時(shí)間實(shí)時(shí)更換數(shù)據(jù)。
接來(lái)下,我們采用在paintEvent中繪制的方式進(jìn)行實(shí)時(shí)波形圖繪制,首先,我們先展示下顯示效果吧!
數(shù)據(jù)來(lái)源依舊是硬件傳入的實(shí)時(shí)數(shù)據(jù),如下:
[0,3,5,8,10,13,15,18,20,23,25,28,26,23,20,16,13,11,9,6,4,3,0]
其實(shí)有些人看到這里會(huì)說(shuō),數(shù)據(jù)都有了直接畫出來(lái)不就可以了嗎?
在我們實(shí)際應(yīng)用過(guò)程中,這些硬件上傳的數(shù)據(jù)不是一次性傳出的,而是取決于你操作硬件的頻率以及事件決定的。所以說(shuō),想要一次性拿出一整條數(shù)據(jù)來(lái)繪制,這個(gè)時(shí)機(jī)已經(jīng)晚了。
那么,我們?cè)撊绾问褂胮aintEvent實(shí)時(shí)繪制出波形圖呢?接下來(lái)就來(lái)講解下我的思路吧,如果覺得我的思路比較繁瑣,大家也可以提出來(lái),我也學(xué)習(xí)下,彌補(bǔ)下自己的不足。
繪制思路
1:接收硬件傳入的數(shù)據(jù)
這里使用了SetRealTimeDepthData(stDepthDatastData);意思是:設(shè)置實(shí)時(shí)深度數(shù)據(jù)值。
參數(shù)穿入的是一個(gè)結(jié)構(gòu)體,在使用這個(gè)函數(shù)之前我已經(jīng)將數(shù)據(jù)做了簡(jiǎn)單的處理,包括了深度方向設(shè)置。
比如:當(dāng)深度逐漸變大時(shí),深度方向div是正數(shù),當(dāng)深度逐漸減小時(shí),深度方向div是負(fù)數(shù)。
下面,我展示下我實(shí)際處理后的數(shù)據(jù)值
對(duì)于這些真實(shí)數(shù)據(jù)我設(shè)定了一個(gè)結(jié)構(gòu)體,用于存儲(chǔ)數(shù)據(jù)時(shí)間、深度方向以及具體深度值
structDrawingEffectivePress
intnDiv;//深度方向
intnDepth;//深度值
DWORDdwTime;//記錄當(dāng)前真實(shí)數(shù)據(jù)的時(shí)間
DrawingEffectivePress():nDiv(0),nDepth(0),dwTime(0){}
}
SetRealTimeDepthData具體實(shí)現(xiàn),如下:
voidQDrawingWaveform::SetRealTimeDepthData(stDepthDatastData)
std::lock_guardstd::mutexlck(m_dataMutex);//加鎖進(jìn)行數(shù)據(jù)操作
DrawingEffectivePressstDepth;
stDepth.nDiv=stData.nDiv=01:-1;
stDepth.nDepth=stData.nDepth;
stDepth.dwTime=GetTickCont();
m_vetDepth.push_back(stDepth);
}
代碼講解:
有上述圖片的真實(shí)數(shù)據(jù)來(lái)看,深度的方位是逐漸遞增的,那么在程序中我們采用了1和-1的方式表示,正方向時(shí)都是用1來(lái)表示,負(fù)方向時(shí)都是用-1來(lái)表示。
每有一條真實(shí)數(shù)據(jù)時(shí),都需要記錄當(dāng)前真實(shí)數(shù)據(jù)的具體時(shí)間,用于繪制實(shí)時(shí)的動(dòng)態(tài)走向。
2:定時(shí)器動(dòng)態(tài)刷新頁(yè)面
設(shè)定定時(shí)器每40毫秒刷新一次頁(yè)面:
#defineTimeInterval40//定時(shí)器時(shí)間間隔
定時(shí)器啟動(dòng)m_nTimerId=startTimer(TimeInterval);
3:真實(shí)數(shù)據(jù)處理
這是我們繪制的一個(gè)重點(diǎn),也是比較麻煩的一部分了。
與硬件打過(guò)交道的友友們都知道,硬件數(shù)據(jù)的不穩(wěn)定性,有些時(shí)候看著數(shù)據(jù)的走向是朝下的,因?yàn)槭謩?dòng)操作緣故,偶爾會(huì)有一些浮動(dòng)的數(shù)據(jù),這些數(shù)據(jù)需要篩除,在傳入數(shù)據(jù)之前我已經(jīng)做了處理,這個(gè)問(wèn)題在這篇文章中是不存在的。
使用m_vetDepth存儲(chǔ)了實(shí)際的深度數(shù)據(jù)值。
std::vectorDrawingEffectivePressm_vetDepth;
第一步:每進(jìn)行一次數(shù)據(jù)更新,都需要剔除超時(shí)顯示數(shù)據(jù)。
什么叫做超時(shí)顯示數(shù)據(jù)?
根據(jù)文章一開篇的動(dòng)畫可以看出,波形圖一邊進(jìn)行繪制操作,一邊向左移動(dòng)。
在移動(dòng)過(guò)程中,肯定會(huì)移出左邊界,那么也就代表了當(dāng)前的圖形不需要展示。對(duì)此,我們就需要在每次更新數(shù)據(jù)時(shí),判斷有哪些數(shù)據(jù)是已經(jīng)超過(guò)顯示范圍的,需要進(jìn)行剔除了。
那么,到這里也就遇到了另外一個(gè)問(wèn)題,我們剔除的數(shù)據(jù)是在m_vetDepth中存儲(chǔ)的數(shù)據(jù)嗎?
答案是的,但是為了邏輯簡(jiǎn)單操作,我們需要重新定義一個(gè)結(jié)構(gòu)體,當(dāng)前結(jié)構(gòu)體主要用來(lái)做已經(jīng)繪制成圖形的點(diǎn)的記錄。
std::vectorDrawingEffectivePressm_vetEffectiveDepth;
在當(dāng)前容器中存儲(chǔ)的數(shù)據(jù)一定是具體特定標(biāo)識(shí)的,也就是波形圖的拐點(diǎn)數(shù)據(jù),一個(gè)完整波形的最低點(diǎn)以及最高點(diǎn)。
當(dāng)我們進(jìn)行實(shí)際繪圖時(shí),也是取m_vetEffectiveDepth中的數(shù)據(jù),保證了數(shù)據(jù)邏輯簡(jiǎn)單性。
現(xiàn)在,我們先來(lái)看一看剔除超時(shí)數(shù)據(jù)的實(shí)際代碼,如下:
voidQDrawingWaveform::DeletingTimeoutData()
DWORDdwCurrentTime=GetTickCount();//當(dāng)前時(shí)間
std::vectorDrawingEffectivePress::iteratoritvet=m_vetEffectivePress.begin();
for(itvet;itvet!=m_vetEffectivePress.end();)
DrawingEffectivePressstPoint=*itvet;
if((dwCurrentTime-stPoint.dwPressTime)m_nSingShowTime)
//超過(guò)界面展示范圍,剔除數(shù)據(jù)
itvet=m_vetEffectivePress.erase(itvet++);
else
itvet++;
}
代碼解析:實(shí)時(shí)獲取最新時(shí)間,每次都判斷存儲(chǔ)的硬件操作時(shí)間與設(shè)定的最大值(m_nSingShowTime)進(jìn)行比較。
當(dāng)超過(guò)設(shè)定的時(shí)間時(shí),說(shuō)明圖形已經(jīng)消失在界面上了,就需要剔除數(shù)據(jù)。
第二步:篩查有效數(shù)據(jù),并記錄
上一步驟是剔除超時(shí)數(shù)據(jù),那么我們?cè)撊绾未鎯?chǔ)這些有效數(shù)據(jù)到m_vetEffectivePress容器中呢?
思路:
1:默認(rèn)容器中存儲(chǔ)前兩條數(shù)據(jù)。
2:當(dāng)后續(xù)數(shù)據(jù)來(lái)時(shí),需要與上一條數(shù)據(jù)進(jìn)行判別。
2.1:如果方向一致,說(shuō)明深度一直在遞增或者是遞減,直接替換最后一會(huì)有效數(shù)據(jù)的值即可。
2.2:如果方向不一致,說(shuō)明深度值發(fā)生了變換,可能由向下變成了向上;也可能由向上變成了向下。不再做數(shù)據(jù)替換操作,而是插入一條新數(shù)據(jù)。
3:操作一條數(shù)據(jù)后,進(jìn)行數(shù)據(jù)刪除。
將上述思路轉(zhuǎn)變成代碼,如下:
std::vectorDrawingEffectivePress::iteratoritvet=m_vetPress.begin()
for(itvet;itvet!=m_vetPress.end();)
DrawingEffectivePressstPoint=*itvet;
DrawingEffectivePressstPress;
stPress.dwTime=stPoint.dwTime;
stPress.nDiv=stPoint.nDiv;
stPress.nDepth=stPoint.nDepth;
intnsize=m_vetEffectivePress.size();
if(nsize2)
m_vetEffectivePress.push_back(stPress);
else
//如果當(dāng)前數(shù)據(jù)stPoint與m_vetEffectivePress的最后一位的拐點(diǎn)一致,
//剔除掉m_vetEffectivePress的最后一位,存儲(chǔ)成最新數(shù)據(jù)
if(m_vetEffectivePress[nsize-1].nDiv==stPoint.nDiv)
//更新m_vetEffectivePress的最后一位
m_vetEffectivePress[nsize-1]=stPress;
else
//存儲(chǔ)的最后一位的拐點(diǎn)與當(dāng)前數(shù)值不一致時(shí),直接存儲(chǔ)
m_vetEffectivePress.push_back(stPress);
itvet=m_vetPress.erase(itvet++);
}
4:圖形繪制
經(jīng)過(guò)上述數(shù)據(jù)處理后,我們可以直接在panitEvent中直接繪制出m_vetEffectivePress圖形了。
實(shí)際代碼效果如下:
QPainterpainter(this);
painter.setRenderHint(QPainter::Antialiasing);//抗鋸齒
QPolygonpolygon;
for(inti=0;im_vetEffectivePress.size();i++)
DrawingEffectivePressstPoint=m_vetEffectivePress[i];
intnX=this-CalcRealPointX(stPoint.dwPressTime);
intnY=this-CalcRealPointY(stPoint.nDepth);
polygonQPoint(nX,nY);
painter.drawPolyline(polygon);
代碼解析:根據(jù)實(shí)際數(shù)據(jù)的操作時(shí)間以及具體的深度值,可以確定波形圖的x軸與y軸了。
根據(jù)時(shí)間的變化,就可以讓圖形看起來(lái)是一種動(dòng)起來(lái)的效果。
CalcRealPointX實(shí)際處理
//TODO:計(jì)算,實(shí)際的x軸坐標(biāo)
DWORDdwCurrent=GetTickCount();
intnRectRight=rect().right();
intnMoveOriginal=dwDepthTime-dwCurrent;
doubledMoveLen=nMoveOriginal/8;
intnX=nRectRight+dMoveLen;
returnnX;
代碼解析:實(shí)時(shí)獲取當(dāng)前繪制時(shí)間,并減去結(jié)構(gòu)體中存儲(chǔ)的深度時(shí)間,設(shè)置移動(dòng)長(zhǎng)度(dwMoveOriginal)。
因?yàn)橐蜃笃?,所以,每次用窗口的右?cè)區(qū)域減去就可以了。
注意:我這里使用的是+,因?yàn)槲矣?jì)算得出的偏移長(zhǎng)度一定是一個(gè)負(fù)值。實(shí)時(shí)時(shí)間一定會(huì)比實(shí)際深度時(shí)間大,所以結(jié)果肯定是一個(gè)負(fù)值。
到這里,我們的實(shí)時(shí)圖形繪制算是完成了80%了,想要繪制出連續(xù)的實(shí)時(shí)深度值圖形就可以實(shí)現(xiàn)了。
為什么說(shuō)是80%呢?
因?yàn)檫€有一個(gè)我們需要考慮的問(wèn)題,當(dāng)不是連續(xù)數(shù)據(jù)獲取時(shí),使用QPolygon繪制圖形時(shí),就會(huì)出現(xiàn)以下效果:
當(dāng)我們不是連續(xù)繪制深度值時(shí),間隔一定時(shí)間后,再進(jìn)行繪圖時(shí),就
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- T/CECS 10014-2019建筑給水用納米抗菌不銹鋼塑料復(fù)合管材與管件
- T/CCSAS 042-2023在役常壓儲(chǔ)罐檢驗(yàn)與適用性評(píng)價(jià)技術(shù)規(guī)范
- T/CCOA 47-2023噴淋水蒸發(fā)冷卻式谷物冷卻機(jī)通用技術(shù)條件
- T/CCMA 0069-2019多吊籠有旋轉(zhuǎn)導(dǎo)軌的人貨兩用施工升降機(jī)
- T/CCMA 0064-2018全斷面隧道掘進(jìn)機(jī)環(huán)境與職業(yè)健康安全
- T/CCAS 034-2023油井水泥漿抗水侵試驗(yàn)方法
- T/CBMCA 006-2018生態(tài)多孔纖維棉
- T/CARSA 1.4-2022基于低空無(wú)人機(jī)的高分衛(wèi)星遙感產(chǎn)品真實(shí)性檢驗(yàn)第4部分:激光雷達(dá)數(shù)據(jù)獲取
- T/CAQI 23-2016污廢水處理自清潔回轉(zhuǎn)式格柵
- 2024年度江蘇省二級(jí)注冊(cè)建筑師之法律法規(guī)經(jīng)濟(jì)與施工通關(guān)考試題庫(kù)帶答案解析
- 腸梗阻課件完整版本
- 絲網(wǎng)印刷技術(shù)全套講解
- 《社會(huì)應(yīng)急力量分類分級(jí)測(cè)評(píng)實(shí)施辦法》知識(shí)培訓(xùn)
- 正規(guī)防水補(bǔ)漏合同模板
- 廈門理工學(xué)院應(yīng)屆生畢業(yè)論文答辯模板
- 24秋國(guó)家開放大學(xué)《社會(huì)教育及管理》形考任務(wù)1-3參考答案
- 2024年河北省高考地理試卷(含答案逐題解析)
- 機(jī)床電氣控制技術(shù)(齊占慶)第一章-答案
- 《言語(yǔ)治療技術(shù)》考試復(fù)習(xí)題庫(kù)(附答案)
- 《義務(wù)教育數(shù)學(xué)課程標(biāo)準(zhǔn)(2022年版)》初中內(nèi)容解讀
- DB42-T 2275-2024 消防給水設(shè)施物聯(lián)網(wǎng)系統(tǒng)技術(shù)標(biāo)準(zhǔn)
評(píng)論
0/150
提交評(píng)論