開發儀表、圖表類控制項需處理多樣化圖形:圓形/線性儀表、指針、刻度、標籤、背景玻璃效果、填充樣式 (純色/漸層/圖片)。傳統「功能導向」架構 (如 MS Graph Demo 的 `PieSlice`+`PieGraph`+`PieGraphRenderer`) 導致功能資料與外觀資料耦合,擴充新圖形或填充方式需修改多處。
┌─────────────────────────────────────┐ │ YPaintBase (邏輯組合層) │ ← 負責形狀組合、座標轉換、繪製順序 ├─────────────────────────────────────┤ │ YShapeBase (幾何形狀層) │ ← 圓、矩形、三角形、扇形、指針樣式... ├─────────────────────────────────────┤ │ YFillBase (填充樣式層) │ ← 純色、漸層、圖片、材質、邊框... └─────────────────────────────────────┘
核心原則:形狀不關心填充,填充不關心形狀,邏輯負責組合兩者。
// 填充基底
class YFillBase {
public:
virtual void Draw(CDC* pDC, CRect bounds) = 0;
YPen m_pen; // 邊框
YBrush m_brush; // 填充
};
// 形狀基底
class YShapeBase {
public:
YFillBase* m_pFill = nullptr;
void SetFill(YFillBase* pFill) { m_pFill = pFill; }
virtual void Draw(CDC* pDC) {
if (m_pFill) m_pFill->Draw(pDC, GetBounds());
}
virtual CRect GetBounds() = 0;
};
// 邏輯組合基底
class YPaintBase {
public:
virtual void Draw(CDC* pDC) = 0;
// 組合多個 YShapeBase,處理座標系、旋轉、縮放
};
// 矩形指針 + 漸層填充
YRectangle* pRect = new YRectangle;
YFillGradient* pGrad = new YFillGradient;
pGrad->SetColors(RGB(255,0,0), RGB(255,255,0));
pGrad->SetGradientType(GRADIENT_HORIZONTAL);
pRect->SetFill(pGrad);
pRect->Draw(pDC); // 自動套用漸層填充
// 同一填充套用到圓形背景
YEllipse* pCircle = new YEllipse;
pCircle->SetFill(pGrad); // 共用填充物件
pCircle->Draw(pDC);
class YTriangle : public YShapeBase {
CPoint m_pts[3];
CRect GetBounds() override { /* 計算外接矩形 */ }
// 無需修改任何填充類別
};
// 立即可用:三角形指針、三角形背景、三角形刻度...
class YFillImage : public YFillBase {
CImage m_image;
void Draw(CDC* pDC, CRect rc) override {
m_image.Draw(pDC->m_hDC, rc, /* 重複/拉伸模式 */);
}
};
// 立即可用:圖片填充指針、圖片背景、圖片刻度...
YFillGradient glassFill;
glassFill.Border.Hide();
glassFill.Background.SetGradient(
YColor(20, 240,240,240), YColor(180, 120,120,120),
GRADIENT_FORWARD_DIAGONAL);
YEllipse glassBg; glassBg.SetFill(&glassFill); glassBg.Draw(pDC);
// 高光反射 (兩條弧形區域)
YFillGradient lightFill;
lightFill.Border.Hide();
lightFill.Background.SetSolid(YColor(210, 255,255,255));
YRange range; range.SetFill(&lightFill);
range.SetSweepAngle(24); range.SetPlacement(INSIDE);
range.SetStartAngle(110); range.Draw(pDC);
range.SetStartAngle(136); range.Draw(pDC);
// 環形刻度 + 環繞文字
YScaleCircular scale; scale.SetRadius(80); scale.SetRange(0, 100);
YScaleTextCircular labels;
labels.AddTextHelper(10, RGB(128,128,128)); // 一般刻度
labels.AddTextHelper(12, RGB(255,44,44), TRUE, "黑體"); // 主刻度
labels.AddText("你"); labels.AddText("有沒有"); labels.AddText("想過");
labels.SetType(TEXT_INWARD); // 向心文字
labels.SetOrigin(cx, cy); labels.SetRadius(60);
labels.Draw(pDC);
// 線性刻度 + 傾斜文字
YScaleXY hScale; hScale.SetLength(380); hScale.SetRange(0, 600);
YScaleTextXY hLabels;
hLabels.AddTextHelper(8.5, -30, ALIGN_RIGHT); // -30度傾斜
hLabels.AddText("一月"); hLabels.AddText("二月")...;
hLabels.Draw(pDC);
| 需求變更 | 傳統架構 | 本框架 |
|---|---|---|
| 新增形狀 (五角星) | 修改 Slice、Graph、Renderer | 僅新增 YStar : YShapeBase |
| 新增填充 (材質圖) | 修改所有 Slice 類別 | 僅新增 YFillTexture : YFillBase |
| 圓餅圖轉長條圖 | 重寫整個繪製管線 | 替換 YPaintBase 組合邏輯 |
| 程式碼複用度 | 低 | 極高 (N形狀 × M填充) |
GaugeFramework/
├── Core/
│ ├── YFillBase.h/cpp // 填充體系
│ ├── YShapeBase.h/cpp // 形狀體系
│ └── YPaintBase.h/cpp // 組合邏輯
├── Shapes/
│ ├── YEllipse, YRectangle, YTriangle, YRange, YStar...
├── Fills/
│ ├── YFillSolid, YFillGradient, YFillImage, YFillHatch...
├── Paints/
│ ├── YGaugeCircular, YGaugeLinear, YChartPie, YChartBar...
└── DemoApp/ // MFC 對話式測試程式