程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 構建儀表、圖表控件的繪制框架

構建儀表、圖表控件的繪制框架

編輯:關於VC++

開發環境: 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的 配合使用:

YFillGradient fill;
YEllipse shape;
shape.SetFill (&fill);
shape.Draw(g);
2、透明儀表罩的繪制

表罩由2 個YRange和1個YEllipes,YRange和YEllipes用特定填充。

FillGradient glassFill;
glassFill.Border.Hide();
glassFill.Background.Show();
glassFill.Background.FillColor.SetColor(20,240,240,240);
glassFill.Background.FillEndColor.SetColor(180,120,120,120);
glassFill.Background.SetGradientType (YGradientType_ForwardDiagonal);
YEllipse glassBK;
glassBK.SetFill(&glassFill);
glassBK.Draw(g);
//反光
YFillGradient lightFill;
lightFill.Border.Hide();
lightFill.Background.FillColor.SetColor(210,255,255,255);
lightFill.Background.FillEndColor.SetColor(210,255,255,255);
YRange range;
range.SetStartWidth(width);
range.SetEndWidth(width);
range.SetFill(&lightFill);
range.SetPlacement(Inside);
range.SetSweepAngle(24);
range.SetStartAngle(110);
range.Draw(g);
range.SetStartAngle(136);
range.Draw(g);
3、刻度的繪制

由於框架的原因,可以非常方便的更改刻度的形狀和填充。(加入一個最基 本的刻度)

YScaleTextCircular是環繞文字。

YScaleCircular是環形刻度。

YScaleXY是線型刻度。

4、 圓表,直表與刻度對應的文字

針對圓表的刻度文字的種類和位置定義。

圖 環繞排列文字的四種方式

環繞文字與環形刻度一般同時出現, 這就要求環繞文字必須遵循某種規則,使文字和刻度不重疊上,且很自然。

以下兩圖展示了這種規則的定義。

“向下”文字位置的定義

圖 "向心"文字位置定義

YScaleTextCircular ScaletextCircular;
YTextHelper* pScaletextHelper = NULL;
pScaletextHelper = new YTextHelper;
pScaletextHelper->SetSize(10.f);
pScaletextHelper- >FontColor.SetColor(128,128,128);
ScaletextCircular.AddText (pScaletextHelper);
pScaletextHelper = new YTextHelper;
pScaletextHelper->SetBold(TRUE);
pScaletextHelper- >SetSize(12.f);
pScaletextHelper->SetFontName("黑體 ");
pScaletextHelper->FontColor.SetColor(255,44,44);
ScaletextCircular.AddText(pScaletextHelper);
pScaletextHelper = new YTextHelper;
pScaletextHelper->FontColor.SetColor (51,51,255);
ScaletextCircular.AddText(pScaletextHelper);
ScaletextCircular.SetType(1);
ScaletextCircular.AddText(" 你");
ScaletextCircular.AddText("有沒有");
ScaletextCircular.AddText("想過");
ScaletextCircular.AddText("罐頭");
ScaletextCircular.AddText("的");
ScaletextCircular.AddText("感受");
ScaletextCircular.AddText("?");
ScaletextCircular.SetDefault(FALSE);
ScaletextCircular.SetOrigin(point_this.X,point_this.Y);
ScaletextCircular.SetRadius((int)(cs_this.Width*0.3f));
ScaletextCircular.SetPlacement(Inside);
ScaletextCircular.Draw (g);
pScaletextHelper = NULL;

繪制線型文字

水 平文字

//     ∧
//     │
// Outside │ Inside
//     │
//     │ Inside
//      └───────>
//        Outside
//
YScaleTextXY m_ScaleText;
YTextHelper* pScaletext_helper = NULL;
pScaletext_helper = new YTextHelper;
pScaletext_helper->SetSize(8.5f);
pScaletext_helper- >SetAngle(-30);
pScaletext_helper->SetHorizontal (StringAlignmentFar);
m_ScaleText.AddText(pScaletext_helper);
m_ScaleText.SetMin(0);
m_ScaleText.SetMax(600);
m_ScaleText.SetBoolY(FALSE);
m_ScaleText.SetOrientation (TRUE);
m_ScaleText.SetOrigin(30.f,50.f);
m_ScaleText.SetLength(380.f);
m_ScaleText.Draw(g);
m_ScaleText.AddText("一月");
m_ScaleText.AddText ("二月");
m_ScaleText.AddText("三月");
m_ScaleText.AddText("四月");
m_ScaleText.AddText ("五月");
m_ScaleText.AddText("六月");
m_ScaleText.AddText("七月");
m_ScaleText.SetDefault (FALSE);
m_ScaleText.SetOrigin(30.f,80.f);
m_ScaleText.Draw (g);
pScaletext_helper = NULL;

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved