隨著時間的推移.doc_第1頁
隨著時間的推移.doc_第2頁
隨著時間的推移.doc_第3頁
隨著時間的推移.doc_第4頁
隨著時間的推移.doc_第5頁
已閱讀5頁,還剩6頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

隨著時間的推移,曲線向右平移,同時X軸的時間坐標(biāo)跟著更新。一、如何繪制動態(tài)曲線。所謂動畫,都是一幀一幀的圖像連續(xù)呈現(xiàn)在用戶面前形成的。所以如果你掌握了如何繪制靜態(tài)曲線,那么學(xué)會繪制動態(tài)曲線也不遠(yuǎn)啦,只需要創(chuàng)建一個定時器(比如調(diào)用MFC中的SetTimmer函數(shù)),每隔一定時間(比如1ms),調(diào)用OnPaint或者OnDraw函數(shù),繪制當(dāng)前幀圖像即可。這里需要注意的是,繪制圖像的代碼需要寫在OnPaint或者OnDraw函數(shù)中,因為當(dāng)窗口失效(比如最小化)恢復(fù)后,會重新繪制當(dāng)前窗口,窗口之前的自繪圖像會丟失。而把繪圖代碼寫在OnPaint或者OnDraw中就是為了讓窗口每次重繪時也能重繪你自己畫的圖像,避免出現(xiàn)窗口最小化再恢復(fù)后,自己畫的圖像丟失的尷尬情況。另外繪制當(dāng)前幀圖像之前,記得用InvalidateRect函數(shù)清除上一幀圖像,不然各幀圖像會背景的堆疊。比如我想清除窗口中(0,0)和(100,100)這兩點確定的矩形中的圖像,代碼如下: CRect Rect; Rect.top = 0; Rect.left = 0; Rect.bottom = 100; Rect.right = 100; InvalidateRect(Rect);根據(jù)上面的思路,我們每隔一定時間繪制一幅圖像,可是如果每次繪制的圖像都是完全相同的,那么圖像看起來也是靜態(tài)的。如何讓曲線動起來呢?我們需要為自己繪圖的代碼設(shè)計一個輸入,即在當(dāng)前時刻曲線上各個點的坐標(biāo)信息。隨著時間的推移,令曲線上各個點的坐標(biāo)隨之變化,這樣每次繪圖都是基于當(dāng)前時刻的曲線坐標(biāo)繪制的,控制好曲線坐標(biāo)的變化,也就能讓你繪制的曲線乖乖的動起來。上面提到了曲線上各個點的坐標(biāo)信息,這個信息可以用多種數(shù)據(jù)結(jié)構(gòu)儲存,不過筆者推薦使用STL中的deque數(shù)據(jù)結(jié)構(gòu)儲存。為什么呢?需求決定選擇。讓我們先想想在繪制圖像的過程中需要對這個數(shù)據(jù)進(jìn)行哪些操作。1、需要遍歷這個數(shù)據(jù),獲取各個點的坐標(biāo)以便繪圖,所以選擇的數(shù)據(jù)結(jié)構(gòu)必須有較高的遍歷效率。2、當(dāng)曲線上的點橫向上充滿了橫坐標(biāo)軸提供的顯示范圍,需要將曲線最右邊的點的坐標(biāo)移除,然后在曲線最左邊添加下一個新點的坐標(biāo),以實現(xiàn)曲線向右平移的效果。所以選擇的數(shù)據(jù)結(jié)構(gòu)需要支持前端和后端元素的添加刪除操作,大家很自然會想到隊列。STL中的list容器也能很輕松的實現(xiàn)隊列功能,但是list還支持任意位置元素的添加和刪除操作,功能上的冗余決定了list需要花費更多的時間來實現(xiàn)我們的需求,事實上遍歷一個deque常常比遍歷一個list快幾十倍,原因在這里就不贅述啦。于是,筆者構(gòu)建了這樣的數(shù)據(jù)結(jié)構(gòu)dequepair m_dqDisplayData;隊列中的每個元素是一個pair,pair中存放坐標(biāo)。維護(hù)這個數(shù)據(jù)結(jié)構(gòu)的核心代碼如下: /如果隊列長度超過了X軸方向上可繪的所有點的數(shù)量 if (m_dqDisplayData.size() = XPointNum) /將隊列前端的坐標(biāo)移除 m_dqDisplayData.pop_front(); /在隊列后端添加新的坐標(biāo) m_dqDisplayData.push_back(make_pair(time, value); else m_dqDisplayData.push_back(make_pair(tiem, value); 前面介紹了如何讓靜態(tài)的曲線動起來,下面具體介紹繪制靜態(tài)圖像的主要技能。1、畫圖首先需要找一位畫家,MFC是這樣獲取一位畫家的。CDC *pDC = GetDC();記得這位畫家畫完本幀圖像之后,打發(fā)他走人,閑人咱們養(yǎng)不起。即必須用ReleaseDC(pDC);釋放資源,否則會造成內(nèi)存泄漏,因為GetDC();函數(shù)中分配了一些資源,這些資源關(guān)聯(lián)在pDC指向的內(nèi)存中,如果不調(diào)用ReleaseDC,當(dāng)pDC出作用域后,只是pDC這個32位的指針變量(也可以說它是一個整數(shù)變量)的內(nèi)存釋放了,pDC指向的內(nèi)存沒有機會得到釋放。這里也反映出MFC的一個原則,Get之后需要Release,這兩個函數(shù)往往是成對定義好的。另外,GetDC和ReleaseDC都是CWnd的成員函數(shù),我們需要在哪個窗口上畫圖,就在那個窗口類的OnPaint或者OnDraw函數(shù)中創(chuàng)建一位會在該窗口上畫畫的畫家,其實GetDC中隱含的操作是,創(chuàng)建一位畫家,將自己所在的窗口的繪圖區(qū)作為畫紙交給這位畫家,然后再把畫家返回給用戶。當(dāng)我們直接建立CDC對象時(比如:CDC MemDC;),就需要用其他方法(比如:SelectObject函數(shù))為其選擇畫紙了。2、畫家畫圖之前,首先要準(zhǔn)備好畫圖工具。MFC提供了很多畫圖工具,比如畫刷(CBrush),畫筆(CPen)等。(呵呵,其實筆者也沒用過幾種) /下面就實例化了一個畫實線,寬度為1,顏色為RGB(0, 128, 64)的畫筆 CPen PenForDrawAxis(PS_SOLID, 1, RGB(0, 128, 64); /畫家使用SelectObject技能,將畫筆握入手中 pDC-SelectObject(PenForDrawAxis);另外說明一點:關(guān)于畫筆不再使用后,是否需要調(diào)用PenForDrawAxis.DeleteObject();釋放資源的問題,網(wǎng)上說法不一。各大書籍上,作者們都常常下意識的顯式地調(diào)用了DeleteObject函數(shù),以體現(xiàn)釋放資源的動作。如果需要及時釋放內(nèi)存資源,為后面的程序運行掃清障礙,那顯式的調(diào)用DeleteObject函數(shù)我覺得沒有問題。但是如果說不調(diào)用DeleteObject函數(shù),CPen對象分配的資源就無法釋放,就會造成內(nèi)存泄漏,這點我深表懷疑。因為CPen對象的資源在構(gòu)造函數(shù)中分配,自然在其析構(gòu)函數(shù)中應(yīng)該有對應(yīng)的釋放函數(shù),因為作為MFC用戶來說, 在使用CPen時,根本不知道是否分配了需要顯式釋放的資源。對象應(yīng)該對自己負(fù)責(zé),不應(yīng)該將冗余責(zé)任移交給用戶,這是設(shè)計C+類的基本原則。通俗的說就是,自己干了哪些好事自己心理清楚,走人的時候自己要收拾干凈。微軟在代碼上不會耍流氓吧(雖然其他地方經(jīng)常流氓)。MSDN上的原話是:When an application no longer requires a given pen, it should call the CGdiObject:DeleteObject member function or destroy the CPen object so the resource is no longer in use. An application should not delete a pen when the pen is selected in a device context.要釋放CPen資源,微軟給我們指了兩條明路,第一是:call the CGdiObject:DeleteObject member function,第二是:destroy the CPen object。何為destroy the CPen object,一種方法就是讓對象出作用域,自動調(diào)用析構(gòu)函數(shù)把自己給了結(jié)了??梢姡珻Pen對象即使不調(diào)用DeleteObject,也能在自己出作用域被C+摧毀時,釋放資源。扯遠(yuǎn)啦,扯遠(yuǎn)啦。下面繼續(xù)。3、畫家開始揮筆啦 /將筆移動到(60,220)這個坐標(biāo)指示的位置(只是選地方,還沒落筆) pDC-MoveTo(60, 220); /將筆在紙上從(60,220)拉到(520,550),一條直線誕生了 pDC-LineTo(520, 220); /將筆在紙上從(520,220)移動到(510,223),另外一條直線躍然紙上 pDC-LineTo(510, 223);怎么只能畫直線?曲線是什么?不過是無數(shù)小段的直線。另外,MoveTo和LineTo不必要成對出現(xiàn),一般一條連續(xù)的曲線只需要調(diào)用一次MoveTo。二、如何使用雙緩沖技術(shù)防止畫面閃爍上面介紹了如何繪制動態(tài)曲線,但是這樣繪制動態(tài)曲線往往會出現(xiàn)畫面閃爍的問題。不管是用什么語言什么構(gòu)架畫圖,出現(xiàn)閃爍的根本原因都在于畫面變化不連貫。也許你要問,我每次畫的一幀圖像都只是在上幀圖像的基礎(chǔ)上變化了一點點,怎么就不連貫了。確實如此,不過別忘了我們在畫每幀圖像之前,還調(diào)用了InvalidateRect來清除前一幀圖像,所謂清除,就是用窗口默認(rèn)背景色填充指定矩形區(qū)域,相當(dāng)于在每兩幀圖像之間,實際還插入了一副大煞風(fēng)景的純色背景圖。終于,大家想到了一種辦法,不使用InvalidateRect來清除前一幀圖像,直接重新請一位會在內(nèi)存上畫畫的畫家,將該幀圖像畫在內(nèi)存中的一張新的紙上,然后在窗口上畫畫的畫家使用自己的終極技能BOOL BitBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop );將在內(nèi)存里面畫畫的老實畫家手上的畫直接復(fù)制過來(剽竊可恥,但很管用)。于是,問題解決啦,愛裝B的程序員們給這種方法取了個很拉風(fēng)的名字 - 雙緩沖技術(shù)。這個方法涉及到了以下幾個主要技能:1、誰會在內(nèi)存上畫畫啊? /創(chuàng)建一個會在內(nèi)存中畫畫的畫家 CDC MemDC; MemDC.CreateCompatibleDC(NULL);2、內(nèi)存里面說好給的那種新的紙在哪??? /創(chuàng)建一個內(nèi)存中的圖紙 CBitmap MemBitmap; MemBitmap.CreateCompatibleBitmap(pDC, 800, 600);為什么上面要傳入一個當(dāng)前窗口類中通過GetDC得到的pDC?因為CreateCompatibleBitmap初始化了一個與pDC指定的設(shè)備上下文兼容的位圖,位圖與指定的設(shè)備上下文具有相同的顏色位面數(shù)或相同的每個像素的位數(shù)。你可以試一試,如果此處傳入&MemDC,完啦完啦,畫家怎么畫,圖上都是灰色的線條,郁悶死啦。至于CreateCompatibleBitmap的后面兩個參數(shù),指定的是圖紙的大小,具體指你可以根據(jù)自己窗口大小等實際情況確定,大了無所謂,用不完后面復(fù)制的時候可以截取指定尺寸。3、怎么讓畫家在這張紙上畫畫? /呵呵,醬紫就搞定啦 MemDC.SelectObject(&MemBitmap);4、內(nèi)存中的畫家如何畫畫?完全一樣,只不過是MemDC在揮筆。 MemDC.MoveTo(60, 220); MemDC.LineTo(520, 220); MemDC.LineTo(510, 223);對啦,溫馨提示,大家多半想用一種顏色填充指定矩形區(qū)域,因為InvalidateRect就是干的這事嘛,你把人家擠下來了,自然這事就得自己做啦。 MemDC.FillSolidRect(0, 0, 580, 250, RGB(1,4,1);上面這個函數(shù)表示的是,以圖紙的(0,0)位置(也就是圖紙的最左上角)作為矩形的左上角坐標(biāo),畫一個顏色為RGB(1,4,1),長為580,寬為250的矩形。尺寸什么的大家不必過于糾結(jié),根據(jù)自己的窗口大小,多試幾種尺寸和坐標(biāo),就能找出最合適的參數(shù)了。需要注意的是,MemDC是在MemBitmap上畫畫,所以MemDC調(diào)用函數(shù)傳入的坐標(biāo)是MemBitmap這個圖紙上的坐標(biāo),不是窗口上的坐標(biāo)。4、如何讓在窗口蹲點的那位畫家直接從內(nèi)存畫家手上復(fù)制圖紙? /下面函數(shù)的意思是:在MemDC手中的畫紙上,以(0,0)處作為矩形框的左上角坐標(biāo),拉一個長為580,寬為250的復(fù)制矩形框,這個框框里面框中的圖像復(fù)制到窗口中,復(fù)制矩形框的左上角與窗口的(20,50)處重合。580,250決定了復(fù)制框框的大小,(0,0)決定了復(fù)制框框在MemBitmap上的位置,(20,50)決定了復(fù)制框框在窗口上的位置。 pDC-BitBlt(20, 50, 580, 250, &MemDC, 0, 0, SRCCOPY);下面是部分畫圖代碼,刪除了很多周邊功能,如果不小心多刪到了什么還請大家海涵,主要留著看個思路和框架。1、畫坐標(biāo)軸的函數(shù),你們看,我就是讓 ”內(nèi)存畫家“ - MemDC 畫畫的,表示用了雙緩沖的哦,呵呵。 void CXXXDlg:DrawAxis(CDC &MemDC, LPTSTR TitleForX, LPTSTR TitleForY) /選擇畫坐標(biāo)軸的畫筆 CPen PenForDrawAxis(PS_SOLID, 1, RGB(0, 128, 64); MemDC.SelectObject(PenForDrawAxis); /繪制X軸 MemDC.MoveTo(60, 220); MemDC.LineTo(520, 220); /繪制箭頭 MemDC.LineTo(510, 223); MemDC.LineTo(510, 217); MemDC.LineTo(520, 220); /繪制Y軸 MemDC.MoveTo(60, 220); MemDC.LineTo(60, 30); /繪制箭頭 MemDC.LineTo(57, 40); MemDC.LineTo(63, 40); MemDC.LineTo(60, 30); /設(shè)置文本的顏色 COLORREF OldColor = MemDC.SetTextColor(RGB(255, 255, 0); /繪制標(biāo)注 MemDC.TextOut(480, 230, TitleForX); MemDC.TextOut(40, 10, TitleForY); /還原文本顏色 MemDC.SetTextColor(OldColor); 2、畫圖例的函數(shù)void CXXXDlg:DrawLegend(CDC &MemDC, CPen &PenForDraw, CPen &PenForDrawAB, CPen &PenForDrawBE) /設(shè)置文本的顏色 COLORREF OldColor = MemDC.SetTextColor(RGB(0, 128, 64); /繪制圖例 MemDC.SelectObject(PenForDraw); MemDC.TextOut(530, 30, _T(Global); MemDC.MoveTo(530, 50); MemDC.LineTo(570, 50); MemDC.SelectObject(PenForDrawAB); MemDC.TextOut(530, 70, _T(AB); MemDC.MoveTo(530, 90); MemDC.LineTo(570, 90); MemDC.SelectObject(PenForDrawBE); MemDC.TextOut(530, 110, _T(BE); MemDC.MoveTo(530, 130); MemDC.LineTo(570, 130); /還原文本顏色 MemDC.SetTextColor(OldColor);3、畫曲線的函數(shù)void CXXXDlg:DrawDynamicCurve(CDC &MemDC, CPen &Pen, dequepair &DisplayData, double Proportion) /選擇畫筆 MemDC.SelectObject(Pen); /進(jìn)入臨界區(qū) EnterCriticalSection(&(m_cControllingParameters.m_cCriticalSection); /繪制曲線 if (DisplayData.size() = 2) COORDINATE XPos = 60; for (UINT PointIndex = 1; PointIndex != DisplayData.size(); PointIndex+) MemDC.MoveTo(XPos+, 220 - (COORDINATE)(double)(DisplayDataPointIndex - 1.second) / Proportion); MemDC.LineTo(XPos, 220 - (COORDINATE)(double)(DisplayDataPointIndex.second) / Proportion); /離開臨界區(qū) LeaveCriticalSection(&(m_cControllingParameters.m_cCriticalSection); /還原文本顏色 MemDC.SetTextColor(OldColor);4、重點來

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論