构建仪表、图表控件的绘制框架
開發環境: VS2003 + Windows XP SP2
測試環境: Windows XP SP2
Demo截圖
?
編寫圖形相關的控件需要完成兩部分:1 繪制;2 與窗口類(泛指)集成使之成為控件。本文重點在于“繪制”部分,提出一個較靈活的框架。用VC的GDI+實現框架,并在Demo中簡單封裝成圓表和直表控件。圖一是要實現的目標(圓表、直表等儀表,指示燈,圖表,旋鈕,滑塊等),由這些目標,經需求分析后,設計出框架。
?
圖一
框架的建立
“如果說我比別人看得更遠些,那是因為我站在了巨人的肩上”。.Net上開源圖表控件比較多,在這里我們分析一下MS Graph Demo。圖二 是其繪制Pie圖表的類圖。
?
圖二 MS Graph Demo繪制Pie圖表的結構
PieSlice表示Pie中的單個扇形,_value用來計算百分比,_color是此扇形的填充顏色。
PieSliceCollection是PieSlice集合。
PieGraph類內置一個PieSliceCollection對象,類中其它的數據是描述Pie整體的數據(寬高,邊框寬度,背景顏色……)。
PieGraphRenderer類通過 DrawGraph函數繪制Pie圖,類內置一個PieGraph對象。
此結構有諸如數據結構和算法的分離等的優點,但也有它的局限性。1 它的框架是建立在功能分類上的,如,Pie圖、Bar圖。PieSlice中不僅有功能數據_value還有外觀數據_color。假如不再填充純色,而是填充圖像,那么就必須修改PieSlice,增加_image:Image屬性; PieGraphRenderer也需相應的修改。假設將上述修改擴展到Pie圖表以外的其它類型的圖表,如:Bar圖表、A圖表、B圖表,那么BarSlice、ASlice、BSlice,及三者相應的Renderer類也必須修改,工作量多且重復。2 在應用過程中,當需要把Pie圖對象轉換成Bar圖對象時,MS Graph Demo的現有框架便不能實現。
由此可見,MS Graph Demo的框架不夠靈活,原因在于功能數據和外觀數據沒有分離。
圖三是我所設計的框架,用一句話概述:由YFillBase填充形狀(YShapeBase),邏輯(YPaintBase)負責把形狀組合起來。
?
圖三
框架由三個基礎類YPaintBase,YShapeBase和YFillBase組成。其中YFillBase是填充基礎類(簡稱“填充”),它負責對象顏色、圖像的填充,邊框等。YShapeBase是基本圖形基礎類(簡稱“形狀”),由此類派生出簡單的基本圖形,如:圓,三角,五角星,特殊指針樣式……。YPaintBase是邏輯組合基礎類(簡稱“邏輯”),由YPaintBase把YShapeBase和YFillBase進行組合,構建出復雜圖形,而復雜圖形可由YPaintBase的派生類再次組合。
圖四演示了應用框架構建儀表控件的背景和指針。
圖四
由YShapeBase派生出,將YPointer對象的pShape指向YRectangle對象,就可以得到矩形指針。同理將YBackground對象的pShape指向YRectangle對象,就得到了矩形背景(圖五)。
?
圖五
如果需要升級,添加新的形狀如三角形YTriangle(圖六),也就相應得到了三角型指針和三角形背景。
圖六
同樣由YFillBase派生一種特殊的圖片填充YFillImage(圖七),其它地方的代碼不用修改,就可以得到用這種填充的任意形狀指針和背景。
圖七
在實際項目中,類似指針,背景的元素很多,應用此框架可以使編碼減少,功能倍增,易于升級、維護。
圖九
下圖演示應用框架構建類似MS Graph Demo的Pie圖表和Bar圖表,是不是很容易加入填充圖像和在Pie圖Bar圖間轉換^_^。
圖十
框架的在繪制儀表控件中的應用
1、YFillBase和YShapeBase的配合使用:
?
1.YFillGradient fill;2.?3.YEllipse shape;4.?5.shape.SetFill(&fill);6.?7.shape.Draw(g);2、透明儀表罩的繪制
表罩由2個YRange和1個YEllipes,YRange和YEllipes用特定填充。
01.FillGradient glassFill;02.glassFill.Border.Hide();03.glassFill.Background.Show();04.glassFill.Background.FillColor.SetColor(20,240,240,240);05.glassFill.Background.FillEndColor.SetColor(180,120,120,120);06.glassFill.Background.SetGradientType(YGradientType_ForwardDiagonal);07.YEllipse glassBK;08.glassBK.SetFill(&glassFill);09.glassBK.Draw(g);10.?11.//反光12.YFillGradient lightFill;13.lightFill.Border.Hide();14.lightFill.Background.FillColor.SetColor(210,255,255,255);15.lightFill.Background.FillEndColor.SetColor(210,255,255,255);16.YRange range;17.range.SetStartWidth(width);18.range.SetEndWidth(width);19.range.SetFill(&lightFill);20.range.SetPlacement(Inside);21.range.SetSweepAngle(24);22.range.SetStartAngle(110);23.range.Draw(g);24.range.SetStartAngle(136);25.range.Draw(g);
3、刻度的繪制
由于框架的原因,可以非常方便的更改刻度的形狀和填充。(加入一個最基本的刻度)
?
YScaleTextCircular是環繞文字。
YScaleCircular是環形刻度。
YScaleXY是線型刻度。
?
4、圓表,直表與刻度對應的文字
針對圓表的刻度文字的種類和位置定義。
?
圖 環繞排列文字的四種方式
環繞文字與環形刻度一般同時出現,這就要求環繞文字必須遵循某種規則,使文字和刻度不重疊上,且很自然。
以下兩圖展示了這種規則的定義。
?
“向下”文字位置的定義
?
圖 "向心"文字位置定義
01.YScaleTextCircular ScaletextCircular;02.YTextHelper* pScaletextHelper = NULL;03.pScaletextHelper = new YTextHelper;04.pScaletextHelper->SetSize(10.f);05.pScaletextHelper->FontColor.SetColor(128,128,128);06.ScaletextCircular.AddText(pScaletextHelper);07.pScaletextHelper = new YTextHelper;08.pScaletextHelper->SetBold(TRUE);09.pScaletextHelper->SetSize(12.f);10.pScaletextHelper->SetFontName("黑體");11.pScaletextHelper->FontColor.SetColor(255,44,44);12.ScaletextCircular.AddText(pScaletextHelper);13.pScaletextHelper = new YTextHelper;14.pScaletextHelper->FontColor.SetColor(51,51,255);15.ScaletextCircular.AddText(pScaletextHelper);16.ScaletextCircular.SetType(1);17.ScaletextCircular.AddText("你");18.ScaletextCircular.AddText("有沒有");19.ScaletextCircular.AddText("想過");20.ScaletextCircular.AddText("罐頭");21.ScaletextCircular.AddText("的");22.ScaletextCircular.AddText("感受");23.ScaletextCircular.AddText("?");24.ScaletextCircular.SetDefault(FALSE);25.ScaletextCircular.SetOrigin(point_this.X,point_this.Y);26.ScaletextCircular.SetRadius((int)(cs_this.Width*0.3f));27.ScaletextCircular.SetPlacement(Inside);28.ScaletextCircular.Draw(g);29.pScaletextHelper = NULL;
繪制線型文字
01.水平文字02.// ∧03.// │04.//? Outside │? Inside05.// │06.// │ Inside07.// └───────>08.// Outside 09.//10.YScaleTextXY m_ScaleText;11.YTextHelper* pScaletext_helper = NULL;12.pScaletext_helper = new YTextHelper;13.pScaletext_helper->SetSize(8.5f);14.pScaletext_helper->SetAngle(-30);15.pScaletext_helper->SetHorizontal(StringAlignmentFar);16.m_ScaleText.AddText(pScaletext_helper);17.m_ScaleText.SetMin(0);18.m_ScaleText.SetMax(600);19.m_ScaleText.SetBoolY(FALSE);20.m_ScaleText.SetOrientation(TRUE);21.m_ScaleText.SetOrigin(30.f,50.f);22.m_ScaleText.SetLength(380.f);23.m_ScaleText.Draw(g);24.m_ScaleText.AddText("一月");25.m_ScaleText.AddText("二月");26.m_ScaleText.AddText("三月");27.m_ScaleText.AddText("四月");28.m_ScaleText.AddText("五月");29.m_ScaleText.AddText("六月");30.m_ScaleText.AddText("七月");31.m_ScaleText.SetDefault(FALSE);32.m_ScaleText.SetOrigin(30.f,80.f);33.m_ScaleText.Draw(g);34.pScaletext_helper = NULL;
總結
以上是生活随笔為你收集整理的构建仪表、图表控件的绘制框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 三种常见中文内码的转换方法
- 下一篇: select into from 与 i