圖表控件參考mschart . ocx(5.0版)或mschrt 20 . ocx(6.0版?版),是可視化的嗎?Studio自帶的壹個ActiveX控件有很多屬性和事件,功能非常強大。可以實現柱狀圖、曲線趨勢圖、餅狀圖等。,甚至可以是混合圖表,可以是二維的也可以是三維的圖表,有坐標系也可以沒有坐標系,可以自由配置每壹項的顏色和字體。?
壹個?安裝和使用圖表控件
將圖表控件安裝到使用它的項目中:從項目->;補充?去哪?項目-& gt;組件?然後呢。控件->;註冊了?主動?Xcontrols,選擇圖表控件,然後?ClassWizard會生成相應的c++類,其中CMSChart是從CWnd派生出來的,它是Chart?控件的主類,其他類都是從COleDispatchDriver派生出來的,控制控件中相應的對象,完成各部分的相關功能。比如CvcAxis類就是實現坐標軸相關功能的源代碼。同時,項目的控件工具箱中會出現壹個表示圖表控件的按鈕。使用時,將圖表控件按鈕從工具箱拖到對話框中,並調整其大小。?
圖表控件至少有45個屬性,9個方法,49個事件,這裏就不壹壹列舉了。?
在設計中,我們可以在主屬性頁中修改每個屬性的屬性值:右鍵單擊對話框窗口中的圖表控件,選擇“屬性”菜單項,會彈出主屬性頁對話框,設置屬性值。有些屬性沒有在主屬性頁中列出,只能通過編程來修改。另外,要動態繪制圖表,必須掌握控件的編程控制。?
首先,在對話框類中定義控件變量,以便在編程時操縱控件。例如,對話框類的定義如下:class?CAbcDlg?:?公共?對話{
公共:
CAbcDlg(CWnd*?很明顯?=?NULL);
//{{AFX_DATA(CAbcDlg)
enum?{?國際直撥電話?=?IDD_ABC_DIALOG?};
CMSChartm _ Chart
//}}AFX_DATA
......
};
ActiveX控件的屬性和方法對應於控件內部唯壹的整數索引值。編程時可以通過索引設置或獲取控件的屬性值,也可以通過調用控件的c++類的成員函數(本例為CMSChart)來設置或獲取控件的屬性值和調用控件的方法。比如:?
在CMSChart類實現中,有以下代碼:?CString?CMSChart::GetData(){
CString?結果;
InvokeHelper(0x9,DISPATCH_PROPERTYGET,
佛蒙特州BSTR?(void*)&result,?NULL);
回歸?結果;
}
作廢?CMSChart::SetData(LPCTSTR?lpszNewValue){
靜電?字節?parms[]?= VTS _ BSTR;
InvokeHelper(0x9,DISPATCH_PROPERTYPUT
?VT_EMPTY,?NULL,?parms,lpszNewValue);
}
作廢?CMSChart::Refresh(){
InvokeHelper(DISPID_REFRESH,?
DISPATCH _方法,?VT_EMPTY,?NULL,?NULL);
}
這段代碼顯示屬性“Data”的索引值是0x9,我們可以調用函數SetData來設置圖表中某個點的值。索引值為DISPID_REFRESH的方法?“刷新”,叫它刷新。比如:?CString?str = " 34.5
m _圖表。SetData(str);
m _圖表。刷新();
......
閱讀CMSChart類的實現,會發現有些屬性的值並不是BOOL、CString等普通的數據類型,而是另壹個控件驅動類的類變量,比如?CVcPlot?CMSChart::GetPlot(){
LPDISPATCH?pDispatch
InvokeHelper(0x28,DISPATCH_PROPERTYGET,
VT_DISPATCH,?(void*)&pDispatch,?NULL);
回歸?CVcPlot(pDispatch);
}
在CVcPlot類的實現中,有以下代碼:?CVcAxis?CVcPlot::GetAxis
(龍?axisID,?const?變種&?索引){
LPDISPATCH?pDispatch
靜電?字節?parms[]?=VTS_I4?VTS _ VARIANT
InvokeHelper(0x1f,?DISPATCH_PROPERTYGET,
VT_DISPATCH,?(void*)&pDispatch,?帕爾馬斯?axisID,?& Index);
回歸?CVcAxis(pDispatch);
}
CVcAxis類的實現有以下代碼:?CVcValueScale?CVcAxis::GetValueScale(){
LPDISPATCH?pDispatch
InvokeHelper(0x9,DISPATCH_PROPERTYGET,
VT_DISPATCH,?(void*)&pDispatch,?NULL);
回歸?CVcValueScale(pDispatch);
}
並且CVcValueScale類的實現有如下代碼:?作廢?CVcValueScale::set maximum(double?新值){
靜電?字節?parms[]?= VTS _ R8;
InvokeHelper(0x3,DISPATCH_PROPERTYPUT
VT_EMPTY,?NULL,?parms,new value);
}
這就是圖表控件的靈活性。根據上面的代碼,進行下面的調用:?變種?var
m _圖表。GetPlot()。GetAxis(1,?var)。GetValueScale()
。SetMaximum(50.0);
縱坐標的最大刻度可以設置為50.0。
如果需要處理控件觸發的事件,如Click、MouseDown等,可以通過ClassWizard在對話框類中定義相應的處理函數,實現相關的處理功能。?
兩個?動態繪制圖表示例
在壹個溫度采集系統中,我們希望能實時顯示采集到的溫度值,並用圖表控件繪制曲線圖。
每個溫度項用不同顏色的曲線表示;?
橫坐標是時間,縱坐標是溫度值,都需要滾動顯示;?
每次采樣後刷新屏幕。?
設計思路?
隨著時間的推移,采集的數據越來越多,可能壹屏顯示不完,所以系統打開實時數據庫,存儲采集的實時數據。顯示時,從數據庫中讀取所需時間段的數據。?
編輯對話框資源時,添加水平滾動條和垂直滾動條,配合圖表控件進行滾動顯示。?
啟動對話框的計時器,以采樣間隔進行采樣,並刷新屏幕顯示。?主要相關代碼如下:?布爾?CAbcDlg::OnInitDialog(){
CDialog::OnInitDialog();
pDataDB?=?新的?dbase
//實時數據記錄庫。dbase的基類是CDaoRecordset。
pDataDB-& gt;打開(dbOpenDynaset,?“選擇
*?從哪裏?數據”);
變種?var
m _圖表。GetPlot()。GetAxis(1,var)。GetValueScale()。
SetAuto(FALSE);//不自動標註Y軸刻度。
m _圖表。GetPlot()。GetAxis(1,?var)。GetValueScale()。
SetMaximum(37);//y軸最大刻度
m _圖表。GetPlot()。GetAxis(1,?var)。GetValueScale()。
set minimum(32);//y軸最小刻度
m _圖表。GetPlot()。GetAxis(1,var)。GetValueScale()。
setmajordisdivision(5);//y軸刻度分成5個相等的部分
m _圖表。GetPlot()。GetAxis(1,var)。GetValueScale()。
SetMinorDivision(1);//每個刻度壹個刻度線。
m _圖表。SetColumnCount(3);?//3個溫度項,3條曲線
m _圖表。GetPlot()。GetSeriesCollection()。GetItem(1)。
GetPen()。GetVtColor()。設置(0,?0,?255);//線條顏色
m _圖表。GetPlot()。GetSeriesCollection()。GetItem(2)。
GetPen()。GetVtColor()。集(255,?0,?0);
m _圖表。GetPlot()。GetSeriesCollection()。GetItem(3)。
GetPen()。GetVtColor()。設置(0,?255,?0);
m _圖表。GetPlot()。GetSeriesCollection()。
GetItem(1)。GetPen()。SetWidth(2);//線條寬度
m _圖表。GetPlot()。GetSeriesCollection()。
GetItem(2)。GetPen()。SetWidth(2);
m _圖表。GetPlot()。GetSeriesCollection()。
GetItem(3)。GetPen()。SetWidth(2);
m _圖表。SetRowCount(10);?//壹屏顯示10個采樣時刻。
m _圖表。GetPlot()。GetAxis(0,var)。GetCategoryScale()。
SetAuto(FALSE);//不要自動標註X軸刻度。
m _圖表。GetPlot()。GetAxis(0,var)。GetCategoryScale()。
SetDivisionsPerLabel(1);//壹次壹個標簽
m _圖表。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分鐘。
樣本();//調用采樣函數進行第壹次采樣,記錄倉庫中的數據。
?回歸?真實;?
}
作廢?CAbcDlg::OnTimer(UINT?nIDEvent)?{
樣本();//采樣,並將數據記錄在倉庫中。
如果?(pDataDB-& gt;GetRecordCount()& gt;10)
theApp.nBottomRange?=?pDataDB-& gt;GetRecordCount()-10;
其他
theApp.nBottomRange?=?0;?
//用全局變量保存水平滾動條的範圍值。
m_ScrBottom。SetScrollRange(0,theapp . nbottomrange);
theApp.nBottomPos?=?theApp.nBottomRange
m_ScrBottom。SetScrollPos(theapp . nbottompos);
//修正水平滾動條的顯示。
draw pic();//調用函數刷新曲線顯示。
CDialog::on timer(nIDEvent);
}
作廢?CAbcDlg::DrawPic()?{
夏爾?s[10];
UINT?劃?=?1;
pDataDB-& gt;MoveFirst();
pDataDB-& gt;move(theapp . nbottompos);
//只從數據庫中取出某段時間的數據進行顯示。
什麽時候?((!pDataDB-& gt;IsEOF())?&&?(排?& lt=?10)){
m _圖表。SetRow(行);
m _圖表。SetRowLabel((LPCTSTR)pDataDB
-& gt;m日期時間。格式(" % H:% M ");
//用采樣時間標記X軸。
m _圖表。set column(1);
sprintf(s,?" %6.2f ",pDataDB-& gt;m _ no 1);
m _圖表。SetData((LPCSTR)s);
m _圖表。set column(2);
sprintf(s,?" %6.2f ",pDataDB-& gt;m _ No2);
m _圖表。SetData((LPCSTR)s);
m _圖表。set column(3);
sprintf(s,?" %6.2f ",pDataDB-& gt;m _ No3);
m _圖表。SetData((LPCSTR)s);
pDataDB-& gt;MoveNext();
row++;
}
什麽時候?((排?& lt=?10)){
m _圖表。SetRow(行);
m _圖表。setrow label((LPCTSTR)" ");
m _圖表。GetDataGrid()。SetData(行,1,?0,?1);
//采樣數據小於10點。不會顯示相應的位置。
m _圖表。GetDataGrid()。SetData(行,2,?0,?1);
m _圖表。GetDataGrid()。SetData(行,3,?0,?1);
row++;
}
m _圖表。刷新();
}
作廢?CAbcDlg::on scroll(UINT?nSBCode,?
UINT?NPO,?CScrollBar*?pScrollBar)?{
如果?(pDataDB-& gt;GetRecordCount()& gt;10)
theApp.nBottomRange?=?pDataDB-& gt;GetRecordCount()-10;
其他
theApp.nBottomRange?=?0;
m_ScrBottom。SetScrollRange(0,theapp . nbottomrange);
切換?(nSBCode){
案子?SB_LINERIGHT:
如果?(theApp.nBottomPos?& lt?theApp.nBottomRange){
theApp.nBottomPos?=?theApp.nBottomPos?+?1;
m_ScrBottom。SetScrollPos(theapp . nbottompos);
draw pic();
}
打破;
案子?SB_LINELEFT:
如果?(theApp.nBottomPos?& gt?0){
theApp.nBottomPos?=?theApp.nBottomPos?-?1;
m_ScrBottom。SetScrollPos(theapp . nbottompos);
draw pic();
}
打破;
}
CDialog::on scroll(nsb code,?NPO,?pScrollBar);
}
作廢?CAbcDlg::OnVScroll(UINT?nSBCode,?
UINT?NPO,?CScrollBar*?pScrollBar)?{
變種?var
雙倍?max1,min1,f;
切換?(nSBCode){
案子?SB_LINEDOWN:
f?=?m _圖表。GetPlot()。GetAxis(1,?var)。
GetValueScale()。GetMinimum()?-?1;
如果?(f & gt=0)?{//最小刻度大於或等於0,?妳可以滾動。
m _圖表。GetPlot()。GetAxis(1,?var)。GetValueScale()。
set minimum(f);
f?=?m _圖表。GetPlot()。蓋塔克斯
(1,?var)。GetValueScale()。GetMaximum()?-?1;
m _圖表。GetPlot()。GetAxis(1,?var)。GetValueScale()。
SetMaximum(f);
pScrollBar-& gt;SetScrollPos(pScrollBar-& gt;GetScrollPos()?+?1);
m _圖表。刷新();
}
打破;
案子?SB _陣容:
f?=?m _圖表。GetPlot()。GetAxis(1,?var)。
GetValueScale()。GetMaximum()?+?1;
如果?(f?& lt=?50)?{//最大刻度小於或等於50,?妳可以滾動。
m _圖表。GetPlot()。蓋塔克斯
(1,?var)。GetValueScale()。SetMaximum(f);
f?=?m _圖表。GetPlot()。GetAxis(1,?var)。
GetValueScale()。GetMinimum()?+?1;
m _圖表。GetPlot()。GetAxis(1,?var)。GetValueScale()。
set minimum(f);
pScrollBar-& gt;SetScrollPos(pScrollBar-& gt;GetScrollPos()?-?1);
m _圖表。刷新();
}
打破;
}
CDialog::on scroll(nsb code,?NPO,?pScrollBar);
}
特別註意程序中用到的控件類,比如CVcAxis,需要在AbcDlg.cpp文件的開頭說明:# #include?" VcAxis.h " .?
限於篇幅,本文只是壹個簡單例子的部分代碼。在實際應用中,壹般會有更多的要求,比如:縮放顯示坐標軸;采樣時可能得不到正確的采樣值,曲線顯示可能不連續等。這時候就需要根據需求編寫相應的代碼。