繪制思路:做一個自定義控件插入界面中
具體步驟:
(1)橫軸劃分為若干點,使用Moveto+Lineto連線,定時刷新實現動態效果;
(2)在程序中,使用CPaintDC,CClientDc,CDC,CBitMap,CBrush等繪圖類;
(3)繪圖程序分為幾大部分:注冊類句柄、刷新機制、設定坐標系、繪圖;
部分代碼如下:
BOOL CLineChartCtrl::RegisterWndClass(HINSTANCE hInstance)
{
WNDCLASSW wc;
wc.lpszClassName = TEXT("LineChartCtrl"); // matches class name in client
。。。
return (::RegisterClass(&wc) != 0 ); }
void CLineChartCtrl::InvalidateCtrl()
{
CClientDC dc(this);
CRect rcClient;
GetClientRect(rcClient);
if (m_MemDC.GetSafeHdc() == NULL)
{
m_MemDC.CreateCompatibleDC(&dc);
m_Bitmap.CreateCompatibleBitmap(&dc,rcClient.Width(),rcClient.Height());
m_MemDC.SelectObject(m_Bitmap);
m_MemDC.SetBkColor(RGB(255,255,255)); //靜態背景色
CBrush bkBrush(RGB(160,160,160));
m_MemDC.FillRect(rcClient,&bkBrush);
}
InvalidateRect(rcClient, FALSE);
}
float CLineChartCtrl::SetPos(int nIndex, float nPos)
{
。。。}
void CLineChartCtrl::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect rcClient;
GetClientRect(rcClient);
// draw scale
if (m_MemDC.GetSafeHdc() != NULL)
dc.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &m_MemDC, 0, 0, SRCCOPY);
}
void CLineChartCtrl::DrawSpike()
{
CRect rcClient;
GetClientRect(rcClient);
if (m_MemDC.GetSafeHdc() != NULL) //豎線間隔寬度
{
m_MemDC.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &m_MemDC, 20, 0, SRCCOPY);
// draw scale
CRect rcRight = rcClient;
rcRight.left = rcRight.right - 20;
m_MemDC.SetBkColor(RGB(255,255,255)); //運行時背景色
CBrush bkBrush(RGB(160,160,160));
m_MemDC.FillRect(rcRight,&bkBrush);
static BOOL bDrawVerticle = FALSE;
bDrawVerticle = !bDrawVerticle;
if (bDrawVerticle)
{
CPen pen(PS_SOLID, 1, RGB(128,128,128)); //縱軸色
CPen* pOldPen = m_MemDC.SelectObject(&pen);
m_MemDC.MoveTo(CPoint(rcClient.right-2, rcClient.top));
m_MemDC.LineTo(CPoint(rcClient.right-2, rcClient.bottom));
m_MemDC.SelectObject(pOldPen);
}
int nCount = m_items.GetSize();
CLineChartItem* pItem;
CPoint ptOld, ptNew;
for (int i=0; i<nCount; i++)
{
pItem = m_items.GetAt(i);
float nRange = pItem->m_nUpper - pItem->m_nLower;
ptOld.x = rcRight.left-1; // Minus one to make sure to draw inside the area
ptNew.x = rcRight.right-1;
ptOld.y = (int)((((float)(nRange - pItem->m_nOldPos))/(float)nRange)
* (float)rcRight.Height());
ptNew.y = (int)((((float)(nRange - pItem->m_nPos))/(float)nRange)
* (float)rcRight.Height());
CPen pen(PS_SOLID, 1, pItem->m_colorLine);
CPen* pOldPen = m_MemDC.SelectObject(&pen);
m_MemDC.MoveTo(ptOld);
m_MemDC.LineTo(ptNew);
m_MemDC.SelectObject(pOldPen);
}
}
}
BOOL CLineChartCtrl::Add(COLORREF color, float Upper, float Lower)
{
CLineChartItem* pItem = new CLineChartItem;
pItem->m_colorLine = color;
pItem->m_nLower = Lower;
pItem->m_nUpper = Upper;
pItem->m_nPos = 0;
pItem->m_nOldPos = 0;
try
{
m_items.Add(pItem);
InvalidateCtrl();
return TRUE;
}
catch (CMemoryException* e)
{
if (pItem !=NULL)
delete pItem;
e->Delete();
return FALSE;
}
}
void CLineChartCtrl::Go()
{
DrawSpike();
Invalidate(FALSE);
}
注意的幾點:(1) Windows CE采用unicode,必須寫諸如WNDCLASSW;LoadCursorW;
(2) EVC下的CBrush不能使用兩個參數如CBrush(HS_Cross,RGB(0,0,0));
(3)改動stdAfx.h包含的頭文件;
(4)在void CVoltagecontrolDlg::DoDataExchange(CDataExchange* pDX)里加入 DDX_Control(pDX, IDC_LineChartCtrl, m_LineChart); 在BOOL CVoltagecontrolDlg::OnInitDialog()里加入 m_LineChart.SubclassDlgItem(IDC_LineChartCtrl, this);
(5)在設置自定義空間屬性ID必須為IDC_LineChartCtrl,CLASS為LineChartCtrl,相應程序里的注冊句柄名稱也設成LineChartCtrl;
(6)程序中改變豎線間隔的是其寬度,而畫豎線的時間間隔是2*Timer;
現有的運行效果:
橫軸采用五個Edit控件使時間數值能夠動態變化;圖形繪制從坐標軸右側開始,橫軸隨時間移動; 采樣時間為1S;達到控制精度(error<0.05)要求時停止采集數據并且彈出提示對話框。
問題:(1)運行程序將出現三個警告:位于Wincore.cpp的line 348,349,4199。選擇ignore后,可以運行程序。
(2)縱軸坐標通過實際值標定,且沒有畫出刻度線。