亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Qt中PaintEvent繪制實時波形圖的實現(xiàn)示例

 更新時間:2022年06月06日 15:24:40   作者:中國好公民st  
本文主要介紹了Qt中PaintEvent繪制實時波形圖的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

上一篇文章講述了如何使用控件進行波形圖繪制,雖然很方便,但是也有一些無法避免的問題,比如說:動態(tài)繪制圖形時,想要流暢的進行波動,就必須按照特定的時間實時更換數(shù)據(jù)。

接來下,我們采用在paintEvent中繪制的方式進行實時波形圖繪制,首先,我們先展示下顯示效果吧!

數(shù)據(jù)來源依舊是硬件傳入的實時數(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ù)據(jù)都有了直接畫出來不就可以了嗎?

在我們實際應(yīng)用過程中,這些硬件上傳的數(shù)據(jù)不是一次性傳出的,而是取決于你操作硬件的頻率以及事件決定的。所以說,想要一次性拿出一整條數(shù)據(jù)來繪制,這個時機已經(jīng)晚了。

那么,我們該如何使用paintEvent實時繪制出波形圖呢?接下來就來講解下我的思路吧,如果覺得我的思路比較繁瑣,大家也可以提出來,我也學(xué)習(xí)下,彌補下自己的不足。

繪制思路

1:接收硬件傳入的數(shù)據(jù)

這里使用了SetRealTimeDepthData(stDepthData stData);意思是:設(shè)置實時深度數(shù)據(jù)值。

參數(shù)穿入的是一個結(jié)構(gòu)體,在使用這個函數(shù)之前我已經(jīng)將數(shù)據(jù)做了簡單的處理,包括了深度方向設(shè)置。

比如:當(dāng)深度逐漸變大時,深度方向div是正數(shù),當(dāng)深度逐漸減小時,深度方向div是負(fù)數(shù)。

下面,我展示下我實際處理后的數(shù)據(jù)值

對于這些真實數(shù)據(jù)我設(shè)定了一個結(jié)構(gòu)體,用于存儲數(shù)據(jù)時間、深度方向以及具體深度值

struct DrawingEffectivePress
{
    int nDiv; //深度方向
    int nDepth; //深度值
    DWORD dwTime; //記錄當(dāng)前真實數(shù)據(jù)的時間
    DrawingEffectivePress():nDiv(0),nDepth(0),dwTime(0){}
}

SetRealTimeDepthData具體實現(xiàn),如下:

void QDrawingWaveform::SetRealTimeDepthData(stDepthData stData)
{
    std::lock_guard<std::mutex> lck(m_dataMutex); //加鎖進行數(shù)據(jù)操作
    DrawingEffectivePress stDepth;
    stDepth.nDiv = stData.nDiv>=0?1:-1;
    stDepth.nDepth = stData.nDepth;
    stDepth.dwTime = GetTickCont();
    m_vetDepth.push_back(stDepth);
}

代碼講解:

有上述圖片的真實數(shù)據(jù)來看,深度的方位是逐漸遞增的,那么在程序中我們采用了1和-1的方式表示,正方向時都是用1來表示,負(fù)方向時都是用-1來表示。

每有一條真實數(shù)據(jù)時,都需要記錄當(dāng)前真實數(shù)據(jù)的具體時間,用于繪制實時的動態(tài)走向。

2:定時器動態(tài)刷新頁面

設(shè)定定時器每40毫秒刷新一次頁面:

#define TimeInterval 40 //定時器時間間隔

定時器啟動 m_nTimerId = startTimer(TimeInterval);

3:真實數(shù)據(jù)處理

這是我們繪制的一個重點,也是比較麻煩的一部分了。

與硬件打過交道的友友們都知道,硬件數(shù)據(jù)的不穩(wěn)定性,有些時候看著數(shù)據(jù)的走向是朝下的,因為手動操作緣故,偶爾會有一些浮動的數(shù)據(jù),這些數(shù)據(jù)需要篩除,在傳入數(shù)據(jù)之前我已經(jīng)做了處理,這個問題在這篇文章中是不存在的。

使用m_vetDepth存儲了實際的深度數(shù)據(jù)值。

std::vector<DrawingEffectivePress> m_vetDepth;

第一步:每進行一次數(shù)據(jù)更新,都需要剔除超時顯示數(shù)據(jù)。

什么叫做超時顯示數(shù)據(jù)?

根據(jù)文章一開篇的動畫可以看出,波形圖一邊進行繪制操作,一邊向左移動。

在移動過程中,肯定會移出左邊界,那么也就代表了當(dāng)前的圖形不需要展示。對此,我們就需要在每次更新數(shù)據(jù)時,判斷有哪些數(shù)據(jù)是已經(jīng)超過顯示范圍的,需要進行剔除了。

那么,到這里也就遇到了另外一個問題,我們剔除的數(shù)據(jù)是在m_vetDepth中存儲的數(shù)據(jù)嗎?

答案是的,但是為了邏輯簡單操作,我們需要重新定義一個結(jié)構(gòu)體,當(dāng)前結(jié)構(gòu)體主要用來做已經(jīng)繪制成圖形的點的記錄。

std::vector<DrawingEffectivePress> m_vetEffectiveDepth;

在當(dāng)前容器中存儲的數(shù)據(jù)一定是具體特定標(biāo)識的,也就是波形圖的拐點數(shù)據(jù),一個完整波形的最低點以及最高點。

當(dāng)我們進行實際繪圖時,也是取m_vetEffectiveDepth中的數(shù)據(jù),保證了數(shù)據(jù)邏輯簡單性。

現(xiàn)在,我們先來看一看剔除超時數(shù)據(jù)的實際代碼,如下:

void QDrawingWaveform::DeletingTimeoutData()
{
    DWORD dwCurrentTime = GetTickCount(); //當(dāng)前時間
    std::vector<DrawingEffectivePress>::iterator itvet = m_vetEffectivePress.begin();
    for (itvet; itvet != m_vetEffectivePress.end();)
    {
	DrawingEffectivePress stPoint = *itvet;
	if ((dwCurrentTime - stPoint.dwPressTime) > m_nSingShowTime)
	{
            //超過界面展示范圍,剔除數(shù)據(jù)
            itvet = m_vetEffectivePress.erase(itvet++);
	}
	else
            itvet++;
    }
}

代碼解析:實時獲取最新時間,每次都判斷存儲的硬件操作時間與設(shè)定的最大值(m_nSingShowTime)進行比較。

當(dāng)超過設(shè)定的時間時,說明圖形已經(jīng)消失在界面上了,就需要剔除數(shù)據(jù)。

第二步:篩查有效數(shù)據(jù),并記錄

上一步驟是剔除超時數(shù)據(jù),那么我們該如何存儲這些有效數(shù)據(jù)到m_vetEffectivePress容器中呢?

思路:

1:默認(rèn)容器中存儲前兩條數(shù)據(jù)。

2:當(dāng)后續(xù)數(shù)據(jù)來時,需要與上一條數(shù)據(jù)進行判別。

2.1:如果方向一致,說明深度一直在遞增或者是遞減,直接替換最后一會有效數(shù)據(jù)的值即可。

2.2:如果方向不一致,說明深度值發(fā)生了變換,可能由向下變成了向上;也可能由向上變成了向下。不再做數(shù)據(jù)替換操作,而是插入一條新數(shù)據(jù)。

3:操作一條數(shù)據(jù)后,進行數(shù)據(jù)刪除。

將上述思路轉(zhuǎn)變成代碼,如下:

std::vector<DrawingEffectivePress>::iterator itvet = m_vetPress.begin()
for (itvet; itvet != m_vetPress.end(); )
{
	DrawingEffectivePress stPoint = *itvet;
	DrawingEffectivePress stPress;
	stPress.dwTime = stPoint.dwTime;
	stPress.nDiv = stPoint.nDiv;
	stPress.nDepth = stPoint.nDepth;
	int nsize = m_vetEffectivePress.size();
	if (nsize < 2)
	{
		m_vetEffectivePress.push_back(stPress);
	}
	else 
	{
            //如果當(dāng)前數(shù)據(jù)stPoint與m_vetEffectivePress的最后一位的拐點一致,
            //剔除掉m_vetEffectivePress的最后一位,存儲成最新數(shù)據(jù)
            if (m_vetEffectivePress[nsize - 1].nDiv == stPoint.nDiv)
            {
                    //更新m_vetEffectivePress的最后一位
                    m_vetEffectivePress[nsize - 1] = stPress;
            }
            else
            {
                    //存儲的最后一位的拐點與當(dāng)前數(shù)值不一致時,直接存儲
                    m_vetEffectivePress.push_back(stPress); 
                        
            }
	}

	itvet = m_vetPress.erase(itvet++);
}

4:圖形繪制

經(jīng)過上述數(shù)據(jù)處理后,我們可以直接在panitEvent中直接繪制出m_vetEffectivePress圖形了。

實際代碼效果如下:

QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing); //抗鋸齒
QPolygon polygon;
for (int i = 0; i < m_vetEffectivePress.size(); i++)
{
	DrawingEffectivePress stPoint = m_vetEffectivePress[i];
	int nX = this->CalcRealPointX(stPoint.dwPressTime);
	int nY = this->CalcRealPointY(stPoint.nDepth);
	polygon << QPoint(nX, nY);
}
painter.drawPolyline(polygon);

代碼解析:根據(jù)實際數(shù)據(jù)的操作時間以及具體的深度值,可以確定波形圖的x軸與y軸了。

根據(jù)時間的變化,就可以讓圖形看起來是一種動起來的效果。

CalcRealPointX實際處理

//TODO:計算,實際的x軸坐標(biāo)
DWORD dwCurrent = GetTickCount();
int nRectRight = rect().right();
int nMoveOriginal = dwDepthTime - dwCurrent;
double dMoveLen = nMoveOriginal / 8;
int nX = nRectRight + dMoveLen;
return nX;

代碼解析:實時獲取當(dāng)前繪制時間,并減去結(jié)構(gòu)體中存儲的深度時間,設(shè)置移動長度(dwMoveOriginal)。

因為要向左偏移,所以,每次用窗口的右側(cè)區(qū)域減去就可以了。

注意:我這里使用的是"+",因為我計算得出的偏移長度一定是一個負(fù)值。實時時間一定會比實際深度時間大,所以結(jié)果肯定是一個負(fù)值。

到這里,我們的實時圖形繪制算是完成了80%了,想要繪制出連續(xù)的實時深度值圖形就可以實現(xiàn)了。

為什么說是80%呢?

因為還有一個我們需要考慮的問題,當(dāng)不是連續(xù)數(shù)據(jù)獲取時,使用QPolygon繪制圖形時,就會出現(xiàn)以下效果:

當(dāng)我們不是連續(xù)繪制深度值時,間隔一定時間后,再進行繪圖時,就會出現(xiàn)上述紅色區(qū)域框出來的詭異現(xiàn)象。

按照實際應(yīng)用的繪制效果就應(yīng)該如同文章剛開始的效果一樣,間隔一定時間后,再次繪制,應(yīng)該還是一條完整的波形數(shù)據(jù)。

QPolygon這個繪制類顯然使用上述代碼是不支持的,即使我們換成了DrawLine的方式,這個問題還是需要被解決的。

此時,我們就需要做一個特殊處理,當(dāng)我們沒有實際深度值數(shù)據(jù)時,需要實時知道當(dāng)前的繪制點在哪個位置,也就是說,在沒有真實數(shù)據(jù)來臨之前,我們需要每間隔一個繪圖數(shù)據(jù)刷新時間,需要繪制一條直線,而不是直接從上一個繪制點直接繪制波形圖。

到此這篇關(guān)于Qt中PaintEvent繪制實時波形圖的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)Qt PaintEvent繪制實時波形圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++改變參數(shù)值的方式小結(jié)

    C++改變參數(shù)值的方式小結(jié)

    本文主要介紹了C++改變參數(shù)值的方式小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • 減少C++代碼編譯時間的簡單方法(必看篇)

    減少C++代碼編譯時間的簡單方法(必看篇)

    下面小編就為大家?guī)硪黄獪p少C++代碼編譯時間的簡單方法(必看篇)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • C++深入講解引用的特點及與指針的區(qū)別

    C++深入講解引用的特點及與指針的區(qū)別

    引用是C++一個很重要的特性,顧名思義是某一個變量或?qū)ο蟮膭e名,對引用的操作與對其所綁定的變量或?qū)ο蟮牟僮魍耆葍r,這篇文章主要給大家總結(jié)介紹了C++中引用的相關(guān)知識點,需要的朋友可以參考下
    2022-05-05
  • C語言關(guān)于include順序不同導(dǎo)致編譯結(jié)果不同的問題

    C語言關(guān)于include順序不同導(dǎo)致編譯結(jié)果不同的問題

    這篇文章主要介紹了在日常調(diào)試C語言中include的順序不同從而影響最后編譯結(jié)果不同的問題,究其原因是寫代碼的習(xí)慣所導(dǎo)致,下面跟小編一起來看看吧
    2022-04-04
  • C++基于先序、中序遍歷結(jié)果重建二叉樹的方法

    C++基于先序、中序遍歷結(jié)果重建二叉樹的方法

    這篇文章主要介紹了C++基于先序、中序遍歷結(jié)果重建二叉樹的方法,結(jié)合實例形式分析了基于C++構(gòu)建二叉樹的相關(guān)操作技巧,需要的朋友可以參考下
    2017-05-05
  • C++ 實現(xiàn)線程安全的頻率限制器(推薦)

    C++ 實現(xiàn)線程安全的頻率限制器(推薦)

    這篇文章主要介紹了在 C++ 中實現(xiàn)一個線程安全的頻率限制器,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • VC++簡單實現(xiàn)關(guān)機、重啟計算機實例代碼

    VC++簡單實現(xiàn)關(guān)機、重啟計算機實例代碼

    這篇文章主要介紹了VC++簡單實現(xiàn)關(guān)機、重啟計算機實例代碼,很實用的功能,需要的朋友可以參考下
    2014-07-07
  • C語言數(shù)據(jù)(整數(shù)、浮點數(shù))在內(nèi)存中的存儲

    C語言數(shù)據(jù)(整數(shù)、浮點數(shù))在內(nèi)存中的存儲

    之前對c語言數(shù)據(jù)存儲一直不太明白,最近仔細(xì)研究了一番,所以下面這篇文章主要給大家介紹了關(guān)于C語言數(shù)據(jù)(整數(shù)、浮點數(shù))在內(nèi)存中存儲的相關(guān)資料,需要的朋友可以參考下
    2021-06-06
  • 使用C++實現(xiàn)FTP上傳和下載

    使用C++實現(xiàn)FTP上傳和下載

    當(dāng)在Windows上使用C++進行FTP上傳和下載時,您可以使用libcurl庫來簡化操作,本文將為大家詳細(xì)介紹具體步驟,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • C++中類型推斷(auto和decltype)的使用

    C++中類型推斷(auto和decltype)的使用

    在C++11之前,每個數(shù)據(jù)類型都需要在編譯時顯示聲明,在運行時限制表達(dá)式的值,但在C++的新版本之后,引入了 auto 和 decltype等關(guān)鍵字,本文就來介紹一下C++中類型推斷(auto和decltype)的使用,感興趣的可以了解一下
    2023-12-12

最新評論