Duilib自定义控件:饼状图控件

用duilib做界面开发,但是窗口需要生成一个饼状图的图表,因为是动态生成,所以决定采用绘图的方式来做。

一开始选择了使用easyx来做,但是一则easyx窗口句柄一方面很麻烦,二来绘制出来的图效果很差,需要进行抗锯齿修复,但是本人学艺不精,抗锯齿对我来说难度较高,所以最后还是选择了简单的gdi+重绘控件来做。

我们的绘图效果要求呢,是这样的一个效果。

分步解析一下。

首先因为是三个模块,我们需要绘制三个扇形。

然后再在中间绘制一个圆形,然后绘制三条折线,在折线上补足文字就OK了。

废话不多说,直接上代码。

这是一个基于CControlUI的CPieChartUI控件,因为只是展示图表,我们不需要对他进行任何功能方面的开发,只需要重写他的DoPaint函数就可以了。

这是头文件PieChartUI.h

 1 #pragma once
 2 #include "duilib.h"
 3 #include <afxdtctl.h>  
 4 #include <gdiplus.h>  
 5 #pragma comment(lib, "gdiplus.lib")  
 6 using namespace Gdiplus;
 7 
 8 #define PI 3.14159265
 9 
10 class CPieChartUI :
11     public CControlUI
12 {
13 public:
14     CPieChartUI(int InUse, int Free, int Error);
15     ~CPieChartUI();
16 
17     bool DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl);
18 
19     // 绘制折线
20     //void PaintPolyline();
21 public:
22     int InUseNum;
23     int FreeNum;
24     int ErrorNum;
25 };

PieChartUI.cpp

  1 #include "stdafx.h"
  2 #include <math.h>
  3 #include "PieChartUI.h"
  4 
  5 CPieChartUI::CPieChartUI(int InUse, int Free, int Error)
  6     :InUseNum(InUse),
  7     FreeNum(Free),
  8     ErrorNum(Error)
  9 {
 10 }
 11 
 12 
 13 CPieChartUI::~CPieChartUI()
 14 {
 15 }
 16 
 17 bool CPieChartUI::DoPaint(HDC hDC, const RECT & rcPaint, CControlUI * pStopControl)
 18 {
 19     // 初始化 GDI+  
 20     GdiplusStartupInput gdiplusStartupInput;
 21     ULONG_PTR gdiplusToken;
 22     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
 23     Gdiplus::Graphics graphics(hDC);
 24 
 25     // 获取当前控件的位置
 26     RECT CtrlPos = this->GetPos();
 27 
 28     // 计算三块扇形数据的总数
 29     int TotalNum = InUseNum + FreeNum + ErrorNum;
 30 
 31     // 获取圆心点坐标
 32     int CenterX = CtrlPos.left + 28 + 75;
 33     int CenterY = CtrlPos.top + 27 + 75;
 34 
 35     // 绘制第一部分的扇形 
 36     Gdiplus::SolidBrush inuseBrush(Color(255, 7, 143, 214));
 37     graphics.SetSmoothingMode(SmoothingMode::SmoothingModeAntiAlias);
 38     REAL startAngle = 180.0f;
 39     REAL sweepAngle = 360.0f * InUseNum / TotalNum;
 40     Gdiplus::Rect ellipseRect(CtrlPos.left+28, CtrlPos.top+27, 150, 150);
 41     graphics.FillPie(&inuseBrush, ellipseRect, startAngle, sweepAngle);
 42     // 绘制百分比信息折线
 43     if (InUseNum != 0)
 44     {
 45         // 计算折线起点坐标,取弧线中点的角度
 46         REAL CenterAngle = (startAngle + sweepAngle / 2);
 47         // 计算折线起点的弧度(C++中cos和sin的参数值是弧度,不是角度)
 48         REAL CenterAngleRad = CenterAngle * PI / 180;
 49         // 计算折线起点的坐标值
 50         REAL PolylineStartX = CenterX + 75 * cos(CenterAngleRad);
 51         REAL PolylineStartY = CenterY + 75 * sin(CenterAngleRad);
 52         // 计算折线中点坐标
 53         REAL PolylineCenterX = (PolylineStartX <= CenterX) ? (PolylineStartX - 15) : (PolylineStartX + 15);
 54         REAL PolylineCenterY = (PolylineStartY <= CenterY) ? (PolylineStartY - 15) : (PolylineStartY + 15);
 55         // 计算折线终点坐标
 56         REAL PolylineEndX = (PolylineStartX <= CenterX) ? (PolylineCenterX - 30) : (PolylineCenterX + 30);
 57         REAL PolylineEndY = PolylineCenterY;
 58         // 绘制折线
 59         Pen PolylinePen(Color(255, 255, 255, 255), 1);
 60         PointF PolylineStart(PolylineStartX, PolylineStartY);
 61         PointF PolylineCenter(PolylineCenterX, PolylineCenterY);
 62         PointF PolylineEnd(PolylineEndX, PolylineEndY);
 63         PointF Polyline[3] = { PolylineStart, PolylineCenter, PolylineEnd };
 64         graphics.DrawLines(&PolylinePen, Polyline, 3);
 65         // 填写百分比数据
 66         SolidBrush brush(Color(255, 255, 255, 255)); // 设置画刷
 67         FontFamily fontfamily(L"微软雅黑"); // 设置字体类型
 68         Gdiplus::Font font(&fontfamily, 14, FontStyleRegular, UnitPixel); // 设置字体
 69         // PointF类对点进行了封装,这里是指定写字的开始点
 70         PointF  pointf((CenterAngle > 90 && CenterAngle <270) ?
 71             PolylineEndX : PolylineEndX - 30
 72             , PolylineEndY - 20);
 73         CStringW PecentStrW;
 74         PecentStrW.Format(L"%d%%", InUseNum * 100 / TotalNum );
 75         graphics.DrawString(PecentStrW, -1, &font, pointf, &brush);
 76     }
 77 
 78     // 绘制扇形 
 79     Gdiplus::SolidBrush freeBrush(Color(255, 204, 134, 0));
 80     startAngle += sweepAngle;
 81     sweepAngle = 360.0f * FreeNum / TotalNum;
 82     ellipseRect = { CtrlPos.left + 38, CtrlPos.top + 37, 130, 130 };
 83     graphics.FillPie(&freeBrush, ellipseRect, startAngle, sweepAngle);
 84     if (FreeNum != 0)
 85     {
 86         REAL CenterAngle = (startAngle + sweepAngle / 2);
 87         REAL CenterAngleRad = CenterAngle * PI / 180;
 88         REAL PolylineStartX = CenterX + 65 * cos(CenterAngleRad);
 89         REAL PolylineStartY = CenterY + 65 * sin(CenterAngleRad);
 90         // 计算折线中点坐标
 91         REAL PolylineCenterX = (PolylineStartX <= CenterX) ? (PolylineStartX - 15) : (PolylineStartX + 15);
 92         REAL PolylineCenterY = (PolylineStartY <= CenterY) ? (PolylineStartY - 15) : (PolylineStartY + 15);
 93         // 计算折线终点坐标
 94         REAL PolylineEndX = (PolylineStartX <= CenterX) ? (PolylineCenterX - 30) : (PolylineCenterX + 30);
 95         REAL PolylineEndY = PolylineCenterY;
 96         // 绘制折线
 97         Pen PolylinePen(Color(255, 255, 255, 255), 1);
 98         PointF PolylineStart(PolylineStartX, PolylineStartY);
 99         PointF PolylineCenter(PolylineCenterX, PolylineCenterY);
100         PointF PolylineEnd(PolylineEndX, PolylineEndY);
101         PointF Polyline[3] = { PolylineStart, PolylineCenter, PolylineEnd };
102         graphics.DrawLines(&PolylinePen, Polyline, 3);
103         // 填写百分比数据
104         SolidBrush brush(Color(255, 255, 255, 255)); // 设置画刷
105         FontFamily fontfamily(L"微软雅黑"); // 设置字体类型
106         Gdiplus::Font font(&fontfamily, 14, FontStyleRegular, UnitPixel); // 设置字体
107         // PointF类对点进行了封装,这里是指定写字的开始点
108         PointF  pointf((CenterAngle > 90 && CenterAngle < 270) ?
109             PolylineEndX : PolylineEndX - 30
110             , PolylineEndY - 20);
111         CStringW PecentStrW;
112         PecentStrW.Format(L"%d%%", FreeNum * 100 / TotalNum);
113         graphics.DrawString(PecentStrW, -1, &font, pointf, &brush);
114     }
115 
116     // 绘制扇形 
117     Gdiplus::SolidBrush errorBrush(Color(255, 215, 74, 67));
118     startAngle += sweepAngle;
119     sweepAngle = 360.0f * ErrorNum / TotalNum;
120     ellipseRect = { CtrlPos.left + 48, CtrlPos.top + 47, 110, 110 };
121     graphics.FillPie(&errorBrush, ellipseRect, startAngle, sweepAngle);
122     if (ErrorNum != 0)
123     {
124         REAL CenterAngle = (startAngle + sweepAngle / 2);
125         REAL CenterAngleRad = CenterAngle * PI / 180;
126         REAL PolylineStartX = CenterX + 55 * cos(CenterAngleRad);
127         REAL PolylineStartY = CenterY + 55 * sin(CenterAngleRad);
128         // 计算折线中点坐标
129         REAL PolylineCenterX = (PolylineStartX <= CenterX) ? (PolylineStartX - 15) : (PolylineStartX + 15);
130         REAL PolylineCenterY = (PolylineStartY <= CenterY) ? (PolylineStartY - 15) : (PolylineStartY + 15);
131         // 计算折线终点坐标
132         REAL PolylineEndX = (PolylineStartX <= CenterX) ? (PolylineCenterX - 30) : (PolylineCenterX + 30);
133         REAL PolylineEndY = PolylineCenterY;
134         // 绘制折线
135         Pen PolylinePen(Color(255, 255, 255, 255), 1);
136         PointF PolylineStart(PolylineStartX, PolylineStartY);
137         PointF PolylineCenter(PolylineCenterX, PolylineCenterY);
138         PointF PolylineEnd(PolylineEndX, PolylineEndY);
139         PointF Polyline[3] = { PolylineStart, PolylineCenter, PolylineEnd };
140         graphics.DrawLines(&PolylinePen, Polyline, 3);
141         // 填写百分比数据
142         SolidBrush brush(Color(255, 255, 255, 255)); // 设置画刷
143         FontFamily fontfamily(L"微软雅黑"); // 设置字体类型
144         Gdiplus::Font font(&fontfamily, 14, FontStyleRegular, UnitPixel); // 设置字体
145         // PointF类对点进行了封装,这里是指定写字的开始点
146         PointF  pointf((CenterAngle > 90 && CenterAngle <270) ?
147             PolylineEndX : PolylineEndX - 30
148             , PolylineEndY - 20);
149         CStringW PecentStrW;
150         PecentStrW.Format(L"%d%%", ErrorNum * 100 / TotalNum);
151         graphics.DrawString(PecentStrW, -1, &font, pointf, &brush);
152     }
153 
154     // 绘制一个圆形
155     Gdiplus::SolidBrush fullBrush(Color(255, 1, 21, 76));
156     ellipseRect = { CtrlPos.left + 68, CtrlPos.top + 67, 70, 70 };
157     graphics.FillEllipse(&fullBrush, ellipseRect);
158 
159     return true;
160 }

调用方式

1    CPieChartUI* NewPieChart = new CPieChartUI(inUseNum, FreeNum, ErrorNum);
2     RoomInfoHor->Add(NewPieChart);
3     NewPieChart->SetFloat(true);
4     NewPieChart->SetPos({ 25,65,0,0 });

猜你喜欢

转载自www.cnblogs.com/ybyjforever/p/12763535.html