鄭恢康 朱 偉
(中國電子科技集團公司第四十一研究所 山東 青島 266555)
目前很多電子測量儀器,如示波器、頻譜分析儀、矢量網絡分析儀等,其測量結果以曲線形式進行顯示。這些儀器軟件通常包括數據采集、數據處理、數據顯示3部分。動態波形的繪制是測試儀器中極為重要的一環[1]。其用于實現數據顯示的繪圖模塊具有較多共通性,含有窗口、多跡線、信息顯示、光標等要素。但因繪圖模塊和系統其他部份相互關聯(例如:繪圖模塊調用采集模塊獲得測量數據),且以源碼的形式嵌入整個系統中,使得繪圖相關的代碼難以復用[2]。
針對上述設計的不足,本文從通用性和復用性的角度出發,應用面向對象的組件化軟件設計方法,設計并實現了一種通用的繪圖模塊。該模塊基于動態鏈接庫(DLL)技術,方便地實現復用、集成和擴展,滿足測量儀器領域的繪圖需求,提高軟件開發效率。
通用繪圖模塊是在Windows下使用Visual Studio 2008開發環境, C++語言開發實現的,它基于MFC類庫實現圖形繪制功能。因此,需在開發環境中創建一個“MFC常規DLL”工程,最終經編譯得到Dll和Lib文件,與相關的頭文件一起提供給用戶。
設計通用繪圖模塊有兩個關鍵點:一是避免模塊依賴于軟件系統,使模塊獨立;二是支持擴展繪圖,滿足特殊的繪圖需求。
為了使模塊獨立,模塊應設計成由上層配置、調用、啟動的方式,而減少模塊對軟件系統的調用[3]。另外,應用面向對象編程依賴倒置的原則[4],使系統與模塊之間不直接依賴于具體實現,而是依賴于接口。
為支持繪圖擴展,應用面向對象編程開閉原則,在模塊內實現共通的、基本的繪圖功能,其他繪圖則通過繪圖組件的方式進行擴展實現,使模塊向修改關閉,向擴展開放[5]。
對于電子測量儀器領域,基本繪圖任務就是曲線的繪制,另外該領域通常以光標的方式進行測量數據的讀取與顯示,這兩部份可作為基本繪圖需求在模塊內實現。而系統功能中涉及到的一些特殊繪圖需求,例如提示信息、參數設置框等,可透過繪圖組件的形式來實現。
基于以上分析,定義以下主要類:
(1) 繪圖接口類CGraphInterface繪圖模塊對外提供的訪問接口。
(2) 繪圖類CGraph實現對跡線、光標、繪圖組件的管理。
(3) 繪圖組件接口CGComponentInf用戶繼承該接口定制繪圖組件,并將指針傳給繪圖類,由繪圖類進行繪制。
(4) 跡線類CTrace實現跡線數據及網格等的繪制。
(5) 光標管理類CMarkerManager實現光標功能,用于繪制光標和光標信息,顯示測量數值。
這幾個主要類之間的關系如圖1所示。

圖1 繪圖模塊UML類圖
另外,對于測量儀器,通常要繪制動態跡線,為了避免繪圖時閃爍,可采用雙緩沖繪圖技術[6],在CGraph類中實現。
該模塊完成測量跡線、坐標網格、刻度標尺等的繪制,將這些視為跡線的屬性,封裝為CTrace類。
2.1.1CGraph類相關設計
為支持多跡線的繪置,在CGraph類組合CTrace類的成員變量,CGraph內部調用CTrace接口進行跡線相關圖形繪制,CGraph對外提供相應的接口進行跡線相關配置。
在CGraph中定義成員變量:
CList
在CGraph中定義跡線操作接口:
(1) 添加跡線void AddTrace(CArray
其中data為傳入的繪圖數據,nTrID為上層為該跡線分配的ID,Graph其他接口通過該ID對指定跡線進行相關操作。
(2) 刪除跡線void DeleteTrace(int nTrID);
(3) 設置跡線刻度void SetTraceScale(double fTop,double fBtm,int nTrID);
(4) 選擇當前跡線void SelectCurTrace(int nTrID);
2.1.2CTrace類設計
CTrace類主要實現測量的數據坐標轉換,以及網格、標尺相關的繪制。
CTrace類定義成員變量,對原始數據和轉換后的繪圖數據進行存放:
CArray
CArray
為支持對多種的坐標格式,應用面向對象編程多態技術[7-8],將與坐標、及坐標轉換相關的函數定義為虛函數,在CTrace派生類中實現。
virtual void DrawGrid(CDC* pDC) = 0;
virtual void DrawScale(CDC* pDC) = 0;
virtual CPoint CalcOnePoint(double fXVal,
double fYVal) = 0;//坐標轉換
該模塊用于讀取跡線上的數值。包括光標狀態及位置的設置、光標位置的繪制、光標信息的繪制,封裝為CMarker類。為支持多個光標,定義CMarkerManager類對一組光標進行管理。由CGraph類集合CMarkerManager類的成員變量,并由CGraph調用CMarkerManager相應接口實現光標功能。
2.2.1CGraph提供的光標功能配置接口
(1) 設置光標顯示狀態void ShowMkr(UINT nMkrID,BOOL bOn);
(2) 設置光標位置void SetMkrPos(UINT nMkrID,UINT nPos);
(3) 光標信息接口void SetMkrInfoInterface(CMkrInfoInterface* pInf);
由于光標信息的格式是因項目而異,因此定義通用的光標信息接口,由CGraph的使用者進行實現,并配置給CGraph。繪圖模塊在繪置光標信息時,調用該接口,以獲得要顯示的光標信息。
CMrkInfoInterface定義接口:
void GetMkrInfo(
UINT nMkrID, //光標ID
UINT nMkrPos,//光標位置
double data[2], //數值
int nTraId, //跡線ID
CStringArray& infoAry, //光標信息
CWordArray& widthAry//光標信息區域劃分
);
2.2.2CMarkerManager類設計
該類定義一組的光標類CMarker成員變量,并提供對指定光標進行設置的接口。
CMarkerManager定義成員變量:
static enum {MKR_NUM = 6};//光標個數
CTrace* m_pTrace; //關聯跡線
CMarker m_mkrs[MKR_NUM]; //光標
CMkrInfoInterface* m_pInfoInf;// 光標信息接口
CMarkerManager提供的接口主要有:
void DrawMkrs(CDC* pDC);
void DrawMkrsInfo(CDC* pDC,CRect& rect);
void AssociateToTrace(CGTrace* pTrace);
void SetMkrInfoInterface(CMkrInfoInterface* pInf);
2.2.3CMarker類設計
該類實現對單個光標位置、狀態、繪制的封裝。
CMarker類定義成員變量:
BOOL m_bOn;//光標狀態
UINT m_nPos;//光標位置
CMarker類提供的接口主要有:
void DrawMkr(CDC* pDC,CPoint pt);
void DrawMkrInfo(CDC* pDC,
CArray
CStringArray& strInfo);
void SetPos(UINT nDataIdx);
該模塊用于配制繪圖區頂部和底部的顯示信息。由CGraph類實現信息區的劃分,通過位置索引的方式來確定顯示的位置,在CGraph類中實現對該信息的繪制。
定義結構體對信息內容和位置進行綁定:
typedef struct _XGraphInfo
{
CString strText; //信息區顯示內空
UINT nRowIdx; //信息區位置橫向索引
UINT nColumIdx;//信息區位置縱向索引
}XGraphInfo;
在CGraph類中,定義下列成員變量存放頂部和底部信息區劃分:
UINT m_nTopInfoRowNum;
UINT m_nTopInfoColumNum;
UINT m_nBtmInfoColumNum;
UINT m_nBtmInfoColumNum;
在CGraph類中,定義下列成員變量存放頂部和底部信息配置:
CArray
CArray
在CGraph類中,定義下列接口進行信息區相應的配置:
void DivideTopInfoZone(UINT nRow,
UINT nColum);//劃分頂部信息區
void DivideBottomInfoZone(UINT nRow,
UINT nColum);//劃分底部信息區
void SetTopInfo(UINT nRowIdx,
UINT nColumIdx,CString str);//設置頂部信息
void SetBottomInfo(UINT nRowIdx,
UINT nColumIdx,CString str);//設置底部信息
繪圖模塊以繪圖組件化擴展的方式來支持使用者在繪圖區自繪制圖形。在Graph中定義隊列成員變量,對繪圖組件的指針進行存儲:
CList< CGComponentInf *, CGComponentInf *> m_pComponentList;
2.4.1CGraph提供的繪圖組件配置接口
void AddComponent(
CGComponentInf* pGComponent);//添加組件
void RemoveComponent(
CGComponentInf* pGComponent);//刪除組件
2.4.2繪圖信息接口類CGInfoInf
繪圖組件需要知道繪圖區域劃分情況,因此定義繪圖信息接口類,提供以下接口:
virtual CRect GetGridRect()=0;//獲取網格區
virtual CRect GetGraphRect()=0;//獲取整個繪圖區
virtual CPoint CalcGraphPoint(double fXValue,
double fYValue) = 0;//數值轉換為繪圖點
這些由CGraph實現,并將指針賦給繪圖組件。
2.4.3繪圖組件接口類CGComponentInf
為了支持在基本繪圖不同縱向位置進行繪制,將基本繪圖分為背景層、網格層、跡線繪制層。繪圖組件接口類提供不同在繪圖層中進行繪制的接口:
virtual void DrawUponBk(CDC* pDC,
CGInfoInf* pGInfo);//在背景層之上繪制
virtual void DrawUponTrace(CDC* pDC,
CGInfoInf* pGInfo);//在跡線層以上繪制
virtual void DrawUponGrid(CDC* pDC,
CGInfoInf* pGInfo);//在網格層之上繪制
以上接口由派生類實現,在CGraph中調用以實現組件繪圖。
對于使用該模塊進行開發的用戶而言,無需知道上述主要類的實現,只需知道CGraphInterface、CGComponentInf的定義。但模塊需對外提供CGraph類對象的創建函數,該函數返回CGraphInterface類型指針。因此,在工程中新建GraphDll.h、GraphDll.cpp,在GraphDll.h中定義該輸出函數,在GraphDll.cpp中實現該函數。
該繪圖模塊已應用在某微波綜合測量儀器中,該類型儀器含有:矢量網絡分析儀器、頻譜儀、矢量電壓計、功率計等多種儀表,透過使用該模塊的基本繪圖功能和組件化繪圖擴展方式,成功地滿足了該項目的繪圖需求。如圖2-圖4所示,證明該模塊具有較好的通用性。

圖2 使用基本繪圖功能繪制跡線

圖3 使用繪圖組件實現參數設置標簽繪制

圖4 使用繪圖組件實現不同繪圖層的繪制
本文設計了一種應用于電子測量儀器領域的通用繪圖模塊,給出模塊的總體設計,各功能模塊的數據結構以及接口設計。該繪圖模塊可實現基本的曲線繪制功能,支持以繪圖組件的方式進行實現自定義繪圖。經過測試, 表明具有易維護、通用性強等優點, 可滿足電子測量儀器的圖形繪制需求。
[1] 楊樂,王厚軍,戴志堅.測試儀器中的動態波形繪制技術[J].儀器儀表學報,2006,27(S2):1159-1160.
[2] 王澤,朱金偉,曲政.基于COM技術的通用繪圖模塊的構建[J].計算機與數字工程,2006,34(8):158-160.
[3] 王湘文,陳建倫,陳紀銘.分層軟件架構設計及其應用研究[J].福建電腦,2011,27(6):55-56.
[4] 高松,牛治永.敏捷設計原則與設計模式的編程實踐——單一職責原則與依賴倒置原則[J].計算機應用,2011,31(S2):149-152.
[5] 郭榮.淺談軟件設計模式中的設計原則[J].信息安全與技術,2015(11):5-6.
[6] 王強,湯小慷,謝存,等.基于GDI與雙緩沖技術的雷達PPI顯示器的仿真[J].科技視界,2016(12):123-123.
[7] 周宇,張立群.面向對象技術的多態性研究[J].電腦與信息技術,2006,14(6):16-19.
[8] 李明明,管志偉.淺析C++多態的作用及實現原理[J].無線互聯科技,2014(7):116-116.