(三十八)c#Winform自定义控件-圆形进度条
程序员文章站
2022-05-29 09:55:44
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control 如果觉得写的还行,请点个 star 支持一下吧 欢迎前来交流探讨: 企鹅群568015492 目录 ......
前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
开源地址:
如果觉得写的还行,请点个 star 支持一下吧
欢迎前来交流探讨: 企鹅群568015492
目录
准备工作
我们理一下思路,进度条支持圆环或扇形显示,支持百分比和数值显示
开始
添加一个用户控件,命名ucprocessellipse
定义2个枚举
1 public enum valuetype 2 { 3 /// <summary> 4 /// 百分比 5 /// </summary> 6 percent, 7 /// <summary> 8 /// 数值 9 /// </summary> 10 absolute 11 } 12 13 public enum showtype 14 { 15 /// <summary> 16 /// 圆环 17 /// </summary> 18 ring, 19 /// <summary> 20 /// 扇形 21 /// </summary> 22 sector 23 }
添加属性
1 [description("值改变事件"), category("自定义")] 2 public event eventhandler valuechanged; 3 4 private color m_backellipsecolor = color.fromargb(22, 160, 133); 5 /// <summary> 6 /// 圆背景色 7 /// </summary> 8 [description("圆背景色"), category("自定义")] 9 public color backellipsecolor 10 { 11 get { return m_backellipsecolor; } 12 set 13 { 14 m_backellipsecolor = value; 15 refresh(); 16 } 17 } 18 19 private color m_coreellipsecolor = color.fromargb(180, 180, 180); 20 /// <summary> 21 /// 内圆颜色,showtype=ring 有效 22 /// </summary> 23 [description("内圆颜色,showtype=ring 有效"), category("自定义")] 24 public color coreellipsecolor 25 { 26 get { return m_coreellipsecolor; } 27 set 28 { 29 m_coreellipsecolor = value; 30 refresh(); 31 } 32 } 33 34 private color m_valuecolor = color.fromargb(255, 77, 59); 35 36 [description("值圆颜色"), category("自定义")] 37 public color valuecolor 38 { 39 get { return m_valuecolor; } 40 set 41 { 42 m_valuecolor = value; 43 refresh(); 44 } 45 } 46 47 private bool m_isshowcoreellipseborder = true; 48 /// <summary> 49 /// 内圆是否显示边框,showtype=ring 有效 50 /// </summary> 51 [description("内圆是否显示边框,showtype=ring 有效"), category("自定义")] 52 public bool isshowcoreellipseborder 53 { 54 get { return m_isshowcoreellipseborder; } 55 set 56 { 57 m_isshowcoreellipseborder = value; 58 refresh(); 59 } 60 } 61 62 private valuetype m_valuetype = valuetype.percent; 63 /// <summary> 64 /// 值文字类型 65 /// </summary> 66 [description("值文字类型"), category("自定义")] 67 public valuetype valuetype 68 { 69 get { return m_valuetype; } 70 set 71 { 72 m_valuetype = value; 73 refresh(); 74 } 75 } 76 77 private int m_valuewidth = 30; 78 /// <summary> 79 /// 外圆值宽度 80 /// </summary> 81 [description("外圆值宽度,showtype=ring 有效"), category("自定义")] 82 public int valuewidth 83 { 84 get { return m_valuewidth; } 85 set 86 { 87 if (value <= 0 || value > math.min(this.width, this.height)) 88 return; 89 m_valuewidth = value; 90 refresh(); 91 } 92 } 93 94 private int m_valuemargin = 5; 95 /// <summary> 96 /// 外圆值间距 97 /// </summary> 98 [description("外圆值间距"), category("自定义")] 99 public int valuemargin 100 { 101 get { return m_valuemargin; } 102 set 103 { 104 if (value < 0 || m_valuemargin >= m_valuewidth) 105 return; 106 m_valuemargin = value; 107 refresh(); 108 } 109 } 110 111 private int m_maxvalue = 100; 112 /// <summary> 113 /// 最大值 114 /// </summary> 115 [description("最大值"), category("自定义")] 116 public int maxvalue 117 { 118 get { return m_maxvalue; } 119 set 120 { 121 if (value > m_value || value <= 0) 122 return; 123 m_maxvalue = value; 124 refresh(); 125 } 126 } 127 128 private int m_value = 0; 129 /// <summary> 130 /// 当前值 131 /// </summary> 132 [description("当前值"), category("自定义")] 133 public int value 134 { 135 get { return m_value; } 136 set 137 { 138 if (m_maxvalue < value || value <= 0) 139 return; 140 m_value = value; 141 if (valuechanged != null) 142 { 143 valuechanged(this, null); 144 } 145 refresh(); 146 } 147 } 148 private font m_font = new font("arial unicode ms", 20); 149 [description("文字字体"), category("自定义")] 150 public override font font 151 { 152 get 153 { 154 return m_font; 155 } 156 set 157 { 158 m_font = value; 159 refresh(); 160 } 161 } 162 color m_forecolor = color.white; 163 [description("文字颜色"), category("自定义")] 164 public override color forecolor 165 { 166 get 167 { 168 return m_forecolor; 169 } 170 set 171 { 172 m_forecolor = value; 173 refresh(); 174 } 175 } 176 177 private showtype m_showtype = showtype.ring; 178 179 [description("显示类型"), category("自定义")] 180 public showtype showtype 181 { 182 get { return m_showtype; } 183 set 184 { 185 m_showtype = value; 186 refresh(); 187 } 188 }
重绘
1 protected override void onpaint(painteventargs e) 2 { 3 base.onpaint(e); 4 5 var g = e.graphics; 6 g.smoothingmode = smoothingmode.antialias; //使绘图质量最高,即消除锯齿 7 g.interpolationmode = interpolationmode.highqualitybicubic; 8 g.compositingquality = compositingquality.highquality; 9 10 int intwidth = math.min(this.size.width, this.size.height); 11 //底圆 12 g.fillellipse(new solidbrush(m_backellipsecolor), new rectangle(new point(0, 0), new size(intwidth, intwidth))); 13 if (m_showtype == hzh_controls.controls.showtype.ring) 14 { 15 //中心圆 16 int intcore = intwidth - m_valuewidth * 2; 17 g.fillellipse(new solidbrush(m_coreellipsecolor), new rectangle(new point(m_valuewidth, m_valuewidth), new size(intcore, intcore))); 18 //中心圆边框 19 if (m_isshowcoreellipseborder) 20 { 21 g.drawellipse(new pen(m_valuecolor, 2), new rectangle(new point(m_valuewidth + 1, m_valuewidth + 1), new size(intcore - 1, intcore - 1))); 22 } 23 if (m_value > 0 && m_maxvalue > 0) 24 { 25 float fltpercent = (float)m_value / (float)m_maxvalue; 26 if (fltpercent > 1) 27 { 28 fltpercent = 1; 29 } 30 31 g.drawarc(new pen(m_valuecolor, m_valuewidth - m_valuemargin * 2), new rectanglef(new point(m_valuewidth / 2 + m_valuemargin / 4, m_valuewidth / 2 + m_valuemargin / 4), new sizef(intwidth - m_valuewidth - m_valuemargin / 2 + (m_valuemargin == 0 ? 0 : 1), intwidth - m_valuewidth - m_valuemargin / 2 + (m_valuemargin == 0 ? 0 : 1))), -90, fltpercent * 360); 32 33 string strvaluetext = m_valuetype == hzh_controls.controls.valuetype.percent ? fltpercent.tostring("0%") : m_value.tostring(); 34 system.drawing.sizef _txtsize = g.measurestring(strvaluetext, this.font); 35 g.drawstring(strvaluetext, this.font, new solidbrush(this.forecolor), new pointf((intwidth - _txtsize.width) / 2 + 1, (intwidth - _txtsize.height) / 2 + 1)); 36 } 37 } 38 else 39 { 40 if (m_value > 0 && m_maxvalue > 0) 41 { 42 float fltpercent = (float)m_value / (float)m_maxvalue; 43 if (fltpercent > 1) 44 { 45 fltpercent = 1; 46 } 47 48 g.fillpie(new solidbrush(m_valuecolor), new rectangle(m_valuemargin, m_valuemargin, intwidth - m_valuemargin * 2, intwidth - m_valuemargin * 2), -90, fltpercent * 360); 49 50 string strvaluetext = m_valuetype == hzh_controls.controls.valuetype.percent ? fltpercent.tostring("0%") : m_value.tostring(); 51 system.drawing.sizef _txtsize = g.measurestring(strvaluetext, this.font); 52 g.drawstring(strvaluetext, this.font, new solidbrush(this.forecolor), new pointf((intwidth - _txtsize.width) / 2 + 1, (intwidth - _txtsize.height) / 2 + 1)); 53 } 54 } 55 56 }
完整代码如下
1 using system; 2 using system.collections.generic; 3 using system.componentmodel; 4 using system.drawing; 5 using system.data; 6 using system.linq; 7 using system.text; 8 using system.windows.forms; 9 using system.drawing.drawing2d; 10 11 namespace hzh_controls.controls 12 { 13 public partial class ucprocessellipse : usercontrol 14 { 15 [description("值改变事件"), category("自定义")] 16 public event eventhandler valuechanged; 17 18 private color m_backellipsecolor = color.fromargb(22, 160, 133); 19 /// <summary> 20 /// 圆背景色 21 /// </summary> 22 [description("圆背景色"), category("自定义")] 23 public color backellipsecolor 24 { 25 get { return m_backellipsecolor; } 26 set 27 { 28 m_backellipsecolor = value; 29 refresh(); 30 } 31 } 32 33 private color m_coreellipsecolor = color.fromargb(180, 180, 180); 34 /// <summary> 35 /// 内圆颜色,showtype=ring 有效 36 /// </summary> 37 [description("内圆颜色,showtype=ring 有效"), category("自定义")] 38 public color coreellipsecolor 39 { 40 get { return m_coreellipsecolor; } 41 set 42 { 43 m_coreellipsecolor = value; 44 refresh(); 45 } 46 } 47 48 private color m_valuecolor = color.fromargb(255, 77, 59); 49 50 [description("值圆颜色"), category("自定义")] 51 public color valuecolor 52 { 53 get { return m_valuecolor; } 54 set 55 { 56 m_valuecolor = value; 57 refresh(); 58 } 59 } 60 61 private bool m_isshowcoreellipseborder = true; 62 /// <summary> 63 /// 内圆是否显示边框,showtype=ring 有效 64 /// </summary> 65 [description("内圆是否显示边框,showtype=ring 有效"), category("自定义")] 66 public bool isshowcoreellipseborder 67 { 68 get { return m_isshowcoreellipseborder; } 69 set 70 { 71 m_isshowcoreellipseborder = value; 72 refresh(); 73 } 74 } 75 76 private valuetype m_valuetype = valuetype.percent; 77 /// <summary> 78 /// 值文字类型 79 /// </summary> 80 [description("值文字类型"), category("自定义")] 81 public valuetype valuetype 82 { 83 get { return m_valuetype; } 84 set 85 { 86 m_valuetype = value; 87 refresh(); 88 } 89 } 90 91 private int m_valuewidth = 30; 92 /// <summary> 93 /// 外圆值宽度 94 /// </summary> 95 [description("外圆值宽度,showtype=ring 有效"), category("自定义")] 96 public int valuewidth 97 { 98 get { return m_valuewidth; } 99 set 100 { 101 if (value <= 0 || value > math.min(this.width, this.height)) 102 return; 103 m_valuewidth = value; 104 refresh(); 105 } 106 } 107 108 private int m_valuemargin = 5; 109 /// <summary> 110 /// 外圆值间距 111 /// </summary> 112 [description("外圆值间距"), category("自定义")] 113 public int valuemargin 114 { 115 get { return m_valuemargin; } 116 set 117 { 118 if (value < 0 || m_valuemargin >= m_valuewidth) 119 return; 120 m_valuemargin = value; 121 refresh(); 122 } 123 } 124 125 private int m_maxvalue = 100; 126 /// <summary> 127 /// 最大值 128 /// </summary> 129 [description("最大值"), category("自定义")] 130 public int maxvalue 131 { 132 get { return m_maxvalue; } 133 set 134 { 135 if (value > m_value || value <= 0) 136 return; 137 m_maxvalue = value; 138 refresh(); 139 } 140 } 141 142 private int m_value = 0; 143 /// <summary> 144 /// 当前值 145 /// </summary> 146 [description("当前值"), category("自定义")] 147 public int value 148 { 149 get { return m_value; } 150 set 151 { 152 if (m_maxvalue < value || value <= 0) 153 return; 154 m_value = value; 155 if (valuechanged != null) 156 { 157 valuechanged(this, null); 158 } 159 refresh(); 160 } 161 } 162 private font m_font = new font("arial unicode ms", 20); 163 [description("文字字体"), category("自定义")] 164 public override font font 165 { 166 get 167 { 168 return m_font; 169 } 170 set 171 { 172 m_font = value; 173 refresh(); 174 } 175 } 176 color m_forecolor = color.white; 177 [description("文字颜色"), category("自定义")] 178 public override color forecolor 179 { 180 get 181 { 182 return m_forecolor; 183 } 184 set 185 { 186 m_forecolor = value; 187 refresh(); 188 } 189 } 190 191 private showtype m_showtype = showtype.ring; 192 193 [description("显示类型"), category("自定义")] 194 public showtype showtype 195 { 196 get { return m_showtype; } 197 set 198 { 199 m_showtype = value; 200 refresh(); 201 } 202 } 203 204 public ucprocessellipse() 205 { 206 initializecomponent(); 207 this.setstyle(controlstyles.allpaintinginwmpaint, true); 208 this.setstyle(controlstyles.doublebuffer, true); 209 this.setstyle(controlstyles.resizeredraw, true); 210 this.setstyle(controlstyles.selectable, true); 211 this.setstyle(controlstyles.supportstransparentbackcolor, true); 212 this.setstyle(controlstyles.userpaint, true); 213 } 214 215 protected override void onpaint(painteventargs e) 216 { 217 base.onpaint(e); 218 219 var g = e.graphics; 220 g.smoothingmode = smoothingmode.antialias; //使绘图质量最高,即消除锯齿 221 g.interpolationmode = interpolationmode.highqualitybicubic; 222 g.compositingquality = compositingquality.highquality; 223 224 int intwidth = math.min(this.size.width, this.size.height); 225 //底圆 226 g.fillellipse(new solidbrush(m_backellipsecolor), new rectangle(new point(0, 0), new size(intwidth, intwidth))); 227 if (m_showtype == hzh_controls.controls.showtype.ring) 228 { 229 //中心圆 230 int intcore = intwidth - m_valuewidth * 2; 231 g.fillellipse(new solidbrush(m_coreellipsecolor), new rectangle(new point(m_valuewidth, m_valuewidth), new size(intcore, intcore))); 232 //中心圆边框 233 if (m_isshowcoreellipseborder) 234 { 235 g.drawellipse(new pen(m_valuecolor, 2), new rectangle(new point(m_valuewidth + 1, m_valuewidth + 1), new size(intcore - 1, intcore - 1))); 236 } 237 if (m_value > 0 && m_maxvalue > 0) 238 { 239 float fltpercent = (float)m_value / (float)m_maxvalue; 240 if (fltpercent > 1) 241 { 242 fltpercent = 1; 243 } 244 245 g.drawarc(new pen(m_valuecolor, m_valuewidth - m_valuemargin * 2), new rectanglef(new point(m_valuewidth / 2 + m_valuemargin / 4, m_valuewidth / 2 + m_valuemargin / 4), new sizef(intwidth - m_valuewidth - m_valuemargin / 2 + (m_valuemargin == 0 ? 0 : 1), intwidth - m_valuewidth - m_valuemargin / 2 + (m_valuemargin == 0 ? 0 : 1))), -90, fltpercent * 360); 246 247 string strvaluetext = m_valuetype == hzh_controls.controls.valuetype.percent ? fltpercent.tostring("0%") : m_value.tostring(); 248 system.drawing.sizef _txtsize = g.measurestring(strvaluetext, this.font); 249 g.drawstring(strvaluetext, this.font, new solidbrush(this.forecolor), new pointf((intwidth - _txtsize.width) / 2 + 1, (intwidth - _txtsize.height) / 2 + 1)); 250 } 251 } 252 else 253 { 254 if (m_value > 0 && m_maxvalue > 0) 255 { 256 float fltpercent = (float)m_value / (float)m_maxvalue; 257 if (fltpercent > 1) 258 { 259 fltpercent = 1; 260 } 261 262 g.fillpie(new solidbrush(m_valuecolor), new rectangle(m_valuemargin, m_valuemargin, intwidth - m_valuemargin * 2, intwidth - m_valuemargin * 2), -90, fltpercent * 360); 263 264 string strvaluetext = m_valuetype == hzh_controls.controls.valuetype.percent ? fltpercent.tostring("0%") : m_value.tostring(); 265 system.drawing.sizef _txtsize = g.measurestring(strvaluetext, this.font); 266 g.drawstring(strvaluetext, this.font, new solidbrush(this.forecolor), new pointf((intwidth - _txtsize.width) / 2 + 1, (intwidth - _txtsize.height) / 2 + 1)); 267 } 268 } 269 270 } 271 } 272 273 public enum valuetype 274 { 275 /// <summary> 276 /// 百分比 277 /// </summary> 278 percent, 279 /// <summary> 280 /// 数值 281 /// </summary> 282 absolute 283 } 284 285 public enum showtype 286 { 287 /// <summary> 288 /// 圆环 289 /// </summary> 290 ring, 291 /// <summary> 292 /// 扇形 293 /// </summary> 294 sector 295 } 296 }
1 namespace hzh_controls.controls 2 { 3 partial class ucprocessellipse 4 { 5 /// <summary> 6 /// 必需的设计器变量。 7 /// </summary> 8 private system.componentmodel.icontainer components = null; 9 10 /// <summary> 11 /// 清理所有正在使用的资源。 12 /// </summary> 13 /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param> 14 protected override void dispose(bool disposing) 15 { 16 if (disposing && (components != null)) 17 { 18 components.dispose(); 19 } 20 base.dispose(disposing); 21 } 22 23 #region 组件设计器生成的代码 24 25 /// <summary> 26 /// 设计器支持所需的方法 - 不要 27 /// 使用代码编辑器修改此方法的内容。 28 /// </summary> 29 private void initializecomponent() 30 { 31 components = new system.componentmodel.container(); 32 this.autoscalemode = system.windows.forms.autoscalemode.font; 33 } 34 35 #endregion 36 } 37 }
用处及效果
最后的话
如果你喜欢的话,请到 点个星 星吧