VC++畫動態曲線

Joey-Zhang發表於2010-05-22

在實驗和生產中,我們常常需要對被監測的物件進行實時監控,比如對現場的溫度等環境因素進行實時資料採集,然後傳輸到主控制計算機,以動態曲線的方式顯示出來,便於人們對現場的瞭解和控制。

(1)使用消隱。(2)使用重繪。其中重繪按照原理的不同又分為3種。

2.1消隱。其實消隱的方法很簡單,主要使用CDC類的成員函式SetROP2 。該函式原型為int SetROP2( int nDrawMode )。引數nDrawMode為新的繪製方式。該函式用來設定當前繪製方式,繪製方式說明畫筆和被填充物件的內部如何與螢幕表面已有的顏色組合。我們選用R2_XORPEN繪製方式——畫筆顏色和螢幕顏色的組合,但不同時在兩者之中,最終畫素=畫筆XOR螢幕畫素。要實現動態曲線只需在這種繪製方式下在原有曲線的位置上再繪一次,以消隱掉原有曲線,再繪製新的曲線,如此重複,就可形成動態曲線。

2.2重繪。在重繪中都要使用到這樣一個函式:CDC類成員函式BitBlt 。原型為BOOL BitBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop )。該函式將一個點陣圖從源裝置描述表拷貝到CDC的裝置描述表中。

2.2.1原理1:設定一個後臺裝置環境。所有的繪圖工作都在後臺完成,然後通過BitBlt 函式拷貝到當前裝置環境。這種方法要求後臺每次都全部重繪,包括座標、字元說明、曲線等。

2.2.2應用舉例:

在OnTimer 函式中每隔一定時間進行重繪。

void CDrawView::OnTimer(UINT nIDEvent)

{ // TODO: Add your message handler code here and/or call default

DrawPicture(); // 畫圖函式

}

 

void CDrawView::DrawPicture()

{

pBackDC->PatBlt(0,0,winx, winy, PATCOPY); //畫座標軸及刻度

DrawCoordinate(pBackDC ,BLACKPEN, MainWindowLeft,MainWindowBottom - MAINHEIGHT, MainWindowLeft + MAINWIDTH, MainWindowBottom); //標出x座標刻度值

WriteCoordinateX(pBackDC, BLACKPEN, MainWindowLeft,MainWindowLeft + MAINWIDTH, MainWindowBottom); //標出y座標刻度值

WriteCoordinateY(pBackDC,BLACKPEN,MainWindowLeft,MainWindowBottom ); //輸出實際寬度值

WriteMessage(pBackDC,MainWindowLeft,MainWindowBottom,MAINHEIGHT );

if ( pBackDC != NULL )

{ //畫曲線圖

DrawGraph(pBackDC,REDPEN,MainWindowLeft+MAINWIDTH,MainWindowBottom);

CDC *pDC = GetDC();

if (pDC != NULL)

{

//呼叫OnDraw()函式,將曲線圖顯示在螢幕中

OnDraw(pDC); ReleaseDC(pDC);

}

}

}

void CDrawView::OnDraw(CDC* pDC)

{

CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);

// TODO: add draw code for native data here

if (pDC != NULL)

pDC->BitBlt(0,0,winx, winy, pBackDC, 0, 0, SRCCOPY);

}

2.2.3原理2:設定一個後臺裝置環境(如圖2),其大小與當前裝置環境相同(如圖1)。但主要繪圖工作都在當前裝置環境進行。例如設當前裝置環境大小為200×100,曲線點之間的間距offset=5,左上角頂點在螢幕中的座標為(200,100)。當所繪製的曲線橫座標X﹤400時,就在當前裝置環境繪製曲線;當橫座標X﹥400時,就從前裝置環境把座標點(205,100)的右下部分用函式BitBlt拷貝到矩形區範圍為(0,0,195,100)的後臺裝置環境中,然後清除當前裝置環境,接著再用函式BitBlt從後臺裝置環境中把曲線拷貝到矩形區範圍為(200,100,195,100)的當前裝置環境中,最後再在曲線尾畫上當前的資料點,如此迴圈。

2.2.4應用舉例:

void CAnimateLineView::OnTimer(UINT nIDEvent)

{ // TODO: Add your message handler code here and/or call default

CClientDC dc(this);

static int x=200;

static int y=200;

CPen pen1(PS_SOLID,0,RGB(255,255,255));

CPen *oldpen1=NULL;

oldpen1=dc.SelectObject(&pen1);

x=x+offsetx;

if(x<=400)

{

dc.MoveTo(x-offsetx,y);

y=200-rand()%90;

dc.LineTo(x,y);

}

else

{

CRect rect(200,100,400,200);

CBrush bkbrush(HS_CROSS,RGB(0,128,0));

m_dc.BitBlt(0,0,195,100,&dc,205,100,SRCCOPY);

dc.SetBkColor(RGB(0,0,0));

dc.FillRect(rect,&bkbrush);

dc.BitBlt(200,100,195,100,&m_dc,0,0,SRCCOPY);

dc.MoveTo(395,y);

y=200-rand()%90;

dc.LineTo(400,y);

}

dc.SelectObject(oldpen1);

CView::OnTimer(nIDEvent);

}

2.2.5原理3:設定一個後臺裝置環境,其寬度為當前裝置環境的兩倍,高度相同。繪圖工作都在後臺裝置環境進行。例如設當前裝置環境大小為200×100(如圖1),則後臺裝置環境為400×100(如圖2),曲線點之間的間距offset=10,左上角頂點在螢幕中的座標為(200,100)。①當在後臺裝置環境中所繪製的曲線橫座標0﹤X﹤200時只需將前半部分割槽域拷貝到當前裝置環境就行了;②當橫座標200﹤X﹤400時,將寬度為200的矩形區域依次向後半部分移動10個單位取出拷貝到當前裝置環境;③當X﹥400時,將後半部分拷貝到當前裝置環境,並清除前半部分。④當第2次0﹤X﹤200時,將後半部分矩形區域依次向後半部分移動10個單位拷貝到當前裝置環境,並將實時曲線畫在前半部分然後將其拷貝到當前裝置環境的末尾;⑤當200﹤X﹤400時,清除後半部分,並將前半部分矩形區域依次向後移動10個單位拷貝到當前裝置環境,在後半部分繪製實時曲線然後將其拷貝到當前裝置環境的末尾;⑥當再次X﹥400時,回到④,如此迴圈下去就能形成動態曲線。

2.2.6應用舉例:

void CLineView::OnTimer(UINT nIDEvent)

{ // TODO: Add your message handler code here and/or call default

static int x=0;

static int y=0;

static int control=0;

CClientDC dc(this);

CRect rect(0,0,200,100);

CRect rect1(200,0,400,100);

CBrush bkbrush(HS_CROSS,RGB(0,128,0));

x=x+offset;

CPen pen1(PS_SOLID,0,RGB(255,255,255));

CPen *oldpen1=NULL;

oldpen1=m_dc.SelectObject(&pen1);

if(x<=200)

{ m_dc.MoveTo(x-offset,y);

y=100-rand()%90;

m_dc.LineTo(x,y);

if(control==0)

dc.BitBlt(200,100,200,100,&m_dc,0,0,SRCCOPY);

else

{

dc.BitBlt(200,100,200-x,100,&m_dc,x+200,0,SRCCOPY);

dc.BitBlt(400-x,100,x,100,&m_dc,0,0,SRCCOPY);

}

}

if(x<=400&&x>200)

{

if(control==1)

{

dc.BitBlt(200,100,200,100,&m_dc,x-200,0,SRCCOPY);

 m_dc.FillRect(rect1,&bkbrush);

control=0;

}

m_dc.MoveTo(x-offset,y);

y=100-rand()%90;

m_dc.LineTo(x,y);

dc.BitBlt(200,100,200,100,&m_dc,x-200,0,SRCCOPY);

}

if(x>400)

{ x=0; dc.BitBlt(200,100,200-x,100,&m_dc,x+200,0,SRCCOPY);

m_dc.SetBkColor(RGB(0,0,0));

m_dc.FillRect(rect,&bkbrush); control=1;

}

dc.SelectObject(oldpen1);

CView::OnTimer(nIDEvent);

}

2.3總結消隱的方法雖然簡單,但不適用於實時監控。當圖形區域要求引數說明和時間同時移動時,重繪中的第2和第3種方法實現起來比較麻煩。重繪中的第1種方法適用性較強,效果最好。

相關文章