Chart控件指Mschart.ocx(5.0版)或Mschrt20.ocx(6.0 版),是Visual Studio自帶的ActiveX控件之一,其屬性、事件不少,功能很是強大,可實現柱狀直方圖、曲線走勢圖、餅狀比例圖等,甚至能夠是混合圖表,能夠是二維或三維圖表,能夠帶或不帶座標系,能夠自由配置各條目的顏色、字體等等。web
Chart控件至少有45個屬性、9個方法、49個事件,在這裏就不一一列舉了。數據庫
在設計中,咱們能夠在主要屬性頁裏修改各屬性的屬性值:右擊對話框窗口中的Chart控件,選擇「Properties」菜單項,就會彈出主要屬性頁對話框,對其中各屬性值進行設置。有些屬性在主要屬性頁裏沒有列出,只能編程修改。另外要動態繪製圖表,必須掌握對控件的編程控制。編程
首先在對話框類中定義控件變量,以便編程時操縱控件。如對話框類定義以下:函數
class CAbcDlg : public CDialog{ public: CAbcDlg(CWnd* pParent = NULL); //{{AFX_DATA(CAbcDlg) enum { IDD = IDD_ABC_DIALOG }; CMSChart m_Chart; //}}AFX_DATA ...... };
ActiveX控件的屬性和方法在控件內部對應惟一一個整數索引值,編程時能夠經過索引來設置或獲取控件的屬性值,也能夠經過調用控件的C++類(在這裏就是CMSChart)的成員函數設置或獲取控件的屬性值及調用控件的方法。例如:工具
在CMSChart類實現中有以下代碼:字體
CString CMSChart::GetData(){ CString result; InvokeHelper(0x9, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL); return result; } void CMSChart::SetData(LPCTSTR lpszNewValue){ static BYTE parms[] =VTS_BSTR; InvokeHelper(0x9, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,lpszNewValue); } void CMSChart::Refresh(){ InvokeHelper(DISPID_REFRESH, DISPATCH_METHOD, VT_EMPTY, NULL, NULL); }
這段代碼代表:屬性「Data」索引值爲0x9,咱們能夠調用函數SetData對圖表中某點的值進行設置。索引值爲DISPID_REFRESH的方法 「Refresh」,調用它進行刷新。如:spa
CString str=「34.5"; m_Chart.SetData(str); m_Chart.Refresh(); ......
閱讀CMSChart類的實現會發現,有些屬性的值不是普通的BOOL、CString等數據類型,而是另外一個控件驅動類的類變量,如:設計
CVcPlot CMSChart::GetPlot(){ LPDISPATCH pDispatch; InvokeHelper(0x28, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL); return CVcPlot(pDispatch); }
在CVcPlot類的實現中有以下代碼:orm
CVcAxis CVcPlot::GetAxis (long axisID, const VARIANT& Index){ LPDISPATCH pDispatch; static BYTE parms[] =VTS_I4 VTS_VARIANT; InvokeHelper(0x1f, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, parms, axisID, &Index); return CVcAxis(pDispatch); }
而CVcAxis類的實現中有以下代碼:對象
CVcValueScale CVcAxis::GetValueScale(){ LPDISPATCH pDispatch; InvokeHelper(0x9, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL); return CVcValueScale(pDispatch); }
而CVcValueScale類的實現中又有以下代碼:
void CVcValueScale::SetMaximum(double newValue){ static BYTE parms[] =VTS_R8; InvokeHelper(0x3, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,newValue); }
這正是Chart控件的靈活性所在,根據上述代碼,以下的調用:
VARIANT var; m_Chart.GetPlot().GetAxis(1, var).GetValueScale() .SetMaximum(50.0); 可實現把縱座標的最大刻度設爲50.0。
控件觸發的事件,如Click、MouseDown等,若是須要處理,能夠經過ClassWizard在對話框類中定義相應的處理函數,實現相關的處理功能。
設計思路
主要相關代碼以下:
BOOL CAbcDlg::OnInitDialog(){ CDialog::OnInitDialog(); pDataDB = new dbase; //實時數據記錄庫,類dbase的基類爲CDaoRecordset pDataDB->Open(dbOpenDynaset, 「select * from data"); VARIANT var; m_Chart.GetPlot().GetAxis(1,var).GetValueScale(). SetAuto(FALSE);//不自動標註y軸刻度 m_Chart.GetPlot().GetAxis(1, var).GetValueScale(). SetMaximum(37);//y軸最大刻度 m_Chart.GetPlot().GetAxis(1, var).GetValueScale(). SetMinimum(32);//y軸最小刻度 m_Chart.GetPlot().GetAxis(1,var).GetValueScale(). SetMajorDivision(5);//y軸刻度5等分 m_Chart.GetPlot().GetAxis(1,var).GetValueScale(). SetMinorDivision(1);//每刻度一個刻度線 m_Chart.SetColumnCount(3); //3個溫度項,3條曲線 m_Chart.GetPlot().GetSeriesCollection().GetItem(1). GetPen().GetVtColor().Set(0, 0, 255);//線色 m_Chart.GetPlot().GetSeriesCollection().GetItem(2). GetPen().GetVtColor().Set(255, 0, 0); m_Chart.GetPlot().GetSeriesCollection().GetItem(3). GetPen().GetVtColor().Set(0, 255, 0); m_Chart.GetPlot().GetSeriesCollection(). GetItem(1).GetPen().SetWidth(2);//線寬 m_Chart.GetPlot().GetSeriesCollection(). GetItem(2).GetPen().SetWidth(2); m_Chart.GetPlot().GetSeriesCollection(). GetItem(3).GetPen().SetWidth(2); m_Chart.SetRowCount(10); //一屏顯示10個採樣時刻 m_Chart.GetPlot().GetAxis(0,var).GetCategoryScale(). SetAuto(FALSE);//不自動標註x軸刻度 m_Chart.GetPlot().GetAxis(0,var).GetCategoryScale(). SetDivisionsPerLabel(1);//每時刻一個標註 m_Chart.GetPlot().GetAxis(0,var).GetCategoryScale(). SetDivisionsPerTick(1);//每時刻一個刻度線 m_ScrLeft.SetScrollRange(0,45); //垂直滾動條可滾動範圍(溫度值範圍0-50, 每滾動1度,一屏顯示5度) m_ScrLeft.SetScrollPos(45-32);//垂直滾動條的當前位置 m_ScrBottom.SetScrollRange(0, 0);//水平滾動條的可滾動範圍 m_ScrBottom.SetScrollPos(0);//水平滾動條的當前位置 SetTimer(23, 300000, NULL);//啓動定時器,定時間隔5分鐘 Sample();//調用採樣函數進行第一次採樣,並把數據記錄入庫 return TRUE; } void CAbcDlg::OnTimer(UINT nIDEvent) { Sample();//採樣,並把數據記錄入庫 if (pDataDB->GetRecordCount()>10) theApp.nBottomRange = pDataDB->GetRecordCount()-10; else theApp.nBottomRange = 0; //用全局變量保存水平滾動條的範圍值 m_ScrBottom.SetScrollRange(0,theApp.nBottomRange); theApp.nBottomPos = theApp.nBottomRange; m_ScrBottom.SetScrollPos(theApp.nBottomPos); //修正水平滾動條的顯示 DrawPic();//調用函數,刷新曲線顯示 CDialog::OnTimer(nIDEvent); } void CAbcDlg::DrawPic() { char s[10]; UINT row = 1; pDataDB->MoveFirst(); pDataDB->Move(theApp.nBottomPos); //只從數據庫中取某時間段的數據進行顯示 while ((!pDataDB->IsEOF()) && (row <= 10)){ m_Chart.SetRow(row); m_Chart.SetRowLabel((LPCTSTR)pDataDB ->m_date_time.Format(「%H:%M")); //以採樣時刻作x軸的標註 m_Chart.SetColumn(1); sprintf(s, 「%6.2f", pDataDB->m_No1); m_Chart.SetData((LPCSTR)s); m_Chart.SetColumn(2); sprintf(s, 「%6.2f", pDataDB->m_No2); m_Chart.SetData((LPCSTR)s); m_Chart.SetColumn(3); sprintf(s, 「%6.2f", pDataDB->m_No3); m_Chart.SetData((LPCSTR)s); pDataDB->MoveNext(); row++; } while ((row <= 10)){ m_Chart.SetRow(row); m_Chart.SetRowLabel((LPCTSTR)「"); m_Chart.GetDataGrid().SetData(row, 1, 0, 1); //採樣數據不足10個點, 對應的位置不顯示 m_Chart.GetDataGrid().SetData(row, 2, 0, 1); m_Chart.GetDataGrid().SetData(row, 3, 0, 1); row++; } m_Chart.Refresh(); } void CAbcDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { if (pDataDB->GetRecordCount()>10) theApp.nBottomRange = pDataDB->GetRecordCount()-10; else theApp.nBottomRange = 0; m_ScrBottom.SetScrollRange(0, theApp.nBottomRange); switch (nSBCode){ case SB_LINERIGHT: if (theApp.nBottomPos < theApp.nBottomRange){ theApp.nBottomPos = theApp.nBottomPos + 1; m_ScrBottom.SetScrollPos(theApp.nBottomPos); DrawPic(); } break; case SB_LINELEFT: if (theApp.nBottomPos > 0){ theApp.nBottomPos = theApp.nBottomPos - 1; m_ScrBottom.SetScrollPos(theApp.nBottomPos); DrawPic(); } break; } CDialog::OnHScroll(nSBCode, nPos, pScrollBar); } void CAbcDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { VARIANT var; double max1,min1,f; switch (nSBCode){ case SB_LINEDOWN: f = m_Chart.GetPlot().GetAxis(1, var). GetValueScale().GetMinimum() - 1; if (f>=0) {//最小刻度大於等於0, 則能夠滾動 m_Chart.GetPlot().GetAxis(1, var).GetValueScale(). SetMinimum(f); f = m_Chart.GetPlot().GetAxis (1, var).GetValueScale().GetMaximum() - 1; m_Chart.GetPlot().GetAxis(1, var).GetValueScale(). SetMaximum(f); pScrollBar->SetScrollPos(pScrollBar->GetScrollPos() + 1); m_Chart.Refresh(); } break; case SB_LINEUP: f = m_Chart.GetPlot().GetAxis(1, var). GetValueScale().GetMaximum() + 1; if (f <= 50) {//最大刻度小於等於50, 則能夠滾動 m_Chart.GetPlot().GetAxis (1, var).GetValueScale().SetMaximum(f); f = m_Chart.GetPlot().GetAxis(1, var). GetValueScale().GetMinimum() + 1; m_Chart.GetPlot().GetAxis(1, var).GetValueScale(). SetMinimum(f); pScrollBar->SetScrollPos(pScrollBar->GetScrollPos() - 1); m_Chart.Refresh(); } break; } CDialog::OnVScroll(nSBCode, nPos, pScrollBar); }
特別注意,程序中用到的關於控件的類,如CVcAxis等,須要在AbcDlg.cpp文件的開始處說明:#include 「VcAxis.h"。
限於篇幅,文中僅僅是一個簡單示例的部分代碼。在實際應用中,通常會有更多的需求,好比:對座標軸進行縮放顯示;採樣有可能得不到正確的採樣值時曲線顯示不連續等等,這時須要根據需求編寫相應代碼。