LoadingCircle.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. //#####################################################################################
  2. //★★★★★★★ http://www.cnpopsoft.com [华普软件] ★★★★★★★
  3. //★★★★★★★ 华普软件-VB、C#专业论文与源码荟萃! ★★★★★★★
  4. //#####################################################################################
  5. using System;
  6. using System.ComponentModel;
  7. using System.Drawing;
  8. using System.Drawing.Drawing2D;
  9. using System.Windows.Forms;
  10. namespace UAS_MES_NEW.CustomControl.SetLoading
  11. {
  12. public partial class LoadingCircle : Control
  13. {
  14. #region 常数
  15. private const double NumberOfDegreesInCircle = 360;
  16. private const double NumberOfDegreesInHalfCircle = NumberOfDegreesInCircle / 2;
  17. private const int DefaultInnerCircleRadius = 8;
  18. private const int DefaultOuterCircleRadius = 10;
  19. private const int DefaultNumberOfSpoke = 10;
  20. private const int DefaultSpokeThickness = 4;
  21. private readonly Color DefaultColor = Color.DarkGray;
  22. private const int MacOSXInnerCircleRadius = 5;
  23. private const int MacOSXOuterCircleRadius = 11;
  24. private const int MacOSXNumberOfSpoke = 12;
  25. private const int MacOSXSpokeThickness = 2;
  26. private const int FireFoxInnerCircleRadius = 6;
  27. private const int FireFoxOuterCircleRadius = 7;
  28. private const int FireFoxNumberOfSpoke = 9;
  29. private const int FireFoxSpokeThickness = 4;
  30. private const int IE7InnerCircleRadius = 8;
  31. private const int IE7OuterCircleRadius = 9;
  32. private const int IE7NumberOfSpoke = 24;
  33. private const int IE7SpokeThickness = 4;
  34. #endregion
  35. #region 枚举
  36. public enum StylePresets
  37. {
  38. MacOSX,
  39. Firefox,
  40. IE7,
  41. Custom
  42. }
  43. #endregion
  44. #region 局部变量
  45. private Timer m_Timer;
  46. private bool m_IsTimerActive;
  47. private int m_NumberOfSpoke;
  48. private int m_SpokeThickness;
  49. private int m_ProgressValue;
  50. private int m_OuterCircleRadius;
  51. private int m_InnerCircleRadius;
  52. private PointF m_CenterPoint;
  53. private Color m_Color;
  54. private Color[] m_Colors;
  55. private double[] m_Angles;
  56. private StylePresets m_StylePreset;
  57. #endregion
  58. #region 属性
  59. /// <summary>
  60. /// 获取和设置控件高亮色
  61. /// </summary>
  62. /// <value>高亮色</value>
  63. [TypeConverter("System.Drawing.ColorConverter"),
  64. Category("LoadingCircle"),
  65. Description("获取和设置控件高亮色")]
  66. public Color Color
  67. {
  68. get
  69. {
  70. return m_Color;
  71. }
  72. set
  73. {
  74. m_Color = value;
  75. GenerateColorsPallet();
  76. Invalidate();
  77. }
  78. }
  79. /// <summary>
  80. /// 获取和设置外围半径
  81. /// </summary>
  82. /// <value>外围半径</value>
  83. [System.ComponentModel.Description("获取和设置外围半径"),
  84. System.ComponentModel.Category("LoadingCircle")]
  85. public int OuterCircleRadius
  86. {
  87. get
  88. {
  89. if (m_OuterCircleRadius == 0)
  90. m_OuterCircleRadius = DefaultOuterCircleRadius;
  91. return m_OuterCircleRadius;
  92. }
  93. set
  94. {
  95. m_OuterCircleRadius = value;
  96. Invalidate();
  97. }
  98. }
  99. /// <summary>
  100. /// 获取和设置内圆半径
  101. /// </summary>
  102. /// <value>内圆半径</value>
  103. [System.ComponentModel.Description("获取和设置内圆半径"),
  104. System.ComponentModel.Category("LoadingCircle")]
  105. public int InnerCircleRadius
  106. {
  107. get
  108. {
  109. if (m_InnerCircleRadius == 0)
  110. m_InnerCircleRadius = DefaultInnerCircleRadius;
  111. return m_InnerCircleRadius;
  112. }
  113. set
  114. {
  115. m_InnerCircleRadius = value;
  116. Invalidate();
  117. }
  118. }
  119. /// <summary>
  120. /// 获取和设置辐条数量
  121. /// </summary>
  122. /// <value>辐条数量</value>
  123. [System.ComponentModel.Description("获取和设置辐条数量"),
  124. System.ComponentModel.Category("LoadingCircle")]
  125. public int NumberSpoke
  126. {
  127. get
  128. {
  129. if (m_NumberOfSpoke == 0)
  130. m_NumberOfSpoke = DefaultNumberOfSpoke;
  131. return m_NumberOfSpoke;
  132. }
  133. set
  134. {
  135. if (m_NumberOfSpoke != value && m_NumberOfSpoke > 0)
  136. {
  137. m_NumberOfSpoke = value;
  138. GenerateColorsPallet();
  139. GetSpokesAngles();
  140. Invalidate();
  141. }
  142. }
  143. }
  144. /// <summary>
  145. /// 获取和设置一个布尔值,表示当前控件<see cref="T:LoadingCircle"/>是否激活。
  146. /// </summary>
  147. /// <value><c>true</c> 表示激活;否则,为<c>false</c>。</value>
  148. [System.ComponentModel.Description("获取和设置一个布尔值,表示当前控件是否激活。"),
  149. System.ComponentModel.Category("LoadingCircle")]
  150. public bool Active
  151. {
  152. get
  153. {
  154. return m_IsTimerActive;
  155. }
  156. set
  157. {
  158. m_IsTimerActive = value;
  159. ActiveTimer();
  160. }
  161. }
  162. /// <summary>
  163. /// 获取和设置辐条粗细程度。
  164. /// </summary>
  165. /// <value>辐条粗细值</value>
  166. [System.ComponentModel.Description("获取和设置辐条粗细程度。"),
  167. System.ComponentModel.Category("LoadingCircle")]
  168. public int SpokeThickness
  169. {
  170. get
  171. {
  172. if (m_SpokeThickness <= 0)
  173. m_SpokeThickness = DefaultSpokeThickness;
  174. return m_SpokeThickness;
  175. }
  176. set
  177. {
  178. m_SpokeThickness = value;
  179. Invalidate();
  180. }
  181. }
  182. /// <summary>
  183. /// 获取和设置旋转速度。
  184. /// </summary>
  185. /// <value>旋转速度</value>
  186. [System.ComponentModel.Description("获取和设置旋转速度。"),
  187. System.ComponentModel.Category("LoadingCircle")]
  188. public int RotationSpeed
  189. {
  190. get
  191. {
  192. return m_Timer.Interval;
  193. }
  194. set
  195. {
  196. if (value > 0)
  197. m_Timer.Interval = value;
  198. }
  199. }
  200. /// <summary>
  201. /// 快速设置预定义风格。
  202. /// </summary>
  203. /// <value>风格的值</value>
  204. [Category("LoadingCircle"),
  205. Description("快速设置预定义风格。"),
  206. DefaultValue(typeof(StylePresets), "Custom")]
  207. public StylePresets StylePreset
  208. {
  209. get { return m_StylePreset; }
  210. set
  211. {
  212. m_StylePreset = value;
  213. switch (m_StylePreset)
  214. {
  215. case StylePresets.MacOSX:
  216. SetCircleAppearance(MacOSXNumberOfSpoke,
  217. MacOSXSpokeThickness, MacOSXInnerCircleRadius,
  218. MacOSXOuterCircleRadius);
  219. break;
  220. case StylePresets.Firefox:
  221. SetCircleAppearance(FireFoxNumberOfSpoke,
  222. FireFoxSpokeThickness, FireFoxInnerCircleRadius,
  223. FireFoxOuterCircleRadius);
  224. break;
  225. case StylePresets.IE7:
  226. SetCircleAppearance(IE7NumberOfSpoke,
  227. IE7SpokeThickness, IE7InnerCircleRadius,
  228. IE7OuterCircleRadius);
  229. break;
  230. case StylePresets.Custom:
  231. SetCircleAppearance(DefaultNumberOfSpoke,
  232. DefaultSpokeThickness,
  233. DefaultInnerCircleRadius,
  234. DefaultOuterCircleRadius);
  235. break;
  236. }
  237. }
  238. }
  239. #endregion
  240. #region 构造函数及事件处理
  241. public LoadingCircle()
  242. {
  243. SetStyle(ControlStyles.UserPaint, true);
  244. SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
  245. SetStyle(ControlStyles.ResizeRedraw, true);
  246. SetStyle(ControlStyles.SupportsTransparentBackColor, true);
  247. m_Color = DefaultColor;
  248. GenerateColorsPallet();
  249. GetSpokesAngles();
  250. GetControlCenterPoint();
  251. m_Timer = new Timer();
  252. m_Timer.Tick += new EventHandler(aTimer_Tick);
  253. ActiveTimer();
  254. this.Resize += new EventHandler(LoadingCircle_Resize);
  255. }
  256. void LoadingCircle_Resize(object sender, EventArgs e)
  257. {
  258. GetControlCenterPoint();
  259. }
  260. void aTimer_Tick(object sender, EventArgs e)
  261. {
  262. m_ProgressValue = ++m_ProgressValue % m_NumberOfSpoke;
  263. Invalidate();
  264. }
  265. protected override void OnPaint(PaintEventArgs e)
  266. {
  267. if (m_NumberOfSpoke > 0)
  268. {
  269. e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
  270. int intPosition = m_ProgressValue;
  271. for (int intCounter = 0; intCounter < m_NumberOfSpoke; intCounter++)
  272. {
  273. intPosition = intPosition % m_NumberOfSpoke;
  274. DrawLine(e.Graphics,
  275. GetCoordinate(m_CenterPoint, m_InnerCircleRadius, m_Angles[intPosition]),
  276. GetCoordinate(m_CenterPoint, m_OuterCircleRadius, m_Angles[intPosition]),
  277. m_Colors[intCounter], m_SpokeThickness);
  278. intPosition++;
  279. }
  280. }
  281. base.OnPaint(e);
  282. }
  283. #endregion
  284. #region 局部方法
  285. private Color Darken(Color _objColor, int _intPercent)
  286. {
  287. int intRed = _objColor.R;
  288. int intGreen = _objColor.G;
  289. int intBlue = _objColor.B;
  290. return Color.FromArgb(_intPercent, Math.Min(intRed, byte.MaxValue), Math.Min(intGreen, byte.MaxValue), Math.Min(intBlue, byte.MaxValue));
  291. }
  292. private void GenerateColorsPallet()
  293. {
  294. m_Colors = GenerateColorsPallet(m_Color, Active, m_NumberOfSpoke);
  295. }
  296. private Color[] GenerateColorsPallet(Color _objColor, bool _blnShadeColor, int _intNbSpoke)
  297. {
  298. Color[] objColors = new Color[NumberSpoke];
  299. byte bytIncrement = (byte)(byte.MaxValue / NumberSpoke);
  300. byte PERCENTAGE_OF_DARKEN = 0;
  301. for (int intCursor = 0; intCursor < NumberSpoke; intCursor++)
  302. {
  303. if (_blnShadeColor)
  304. {
  305. if (intCursor == 0 || intCursor < NumberSpoke - _intNbSpoke)
  306. objColors[intCursor] = _objColor;
  307. else
  308. {
  309. PERCENTAGE_OF_DARKEN += bytIncrement;
  310. if (PERCENTAGE_OF_DARKEN > byte.MaxValue)
  311. PERCENTAGE_OF_DARKEN = byte.MaxValue;
  312. objColors[intCursor] = Darken(_objColor, PERCENTAGE_OF_DARKEN);
  313. }
  314. }
  315. else
  316. objColors[intCursor] = _objColor;
  317. }
  318. return objColors;
  319. }
  320. private void GetControlCenterPoint()
  321. {
  322. m_CenterPoint = GetControlCenterPoint(this);
  323. }
  324. private PointF GetControlCenterPoint(Control _objControl)
  325. {
  326. return new PointF(_objControl.Width / 2, _objControl.Height / 2 - 1);
  327. }
  328. private void DrawLine(Graphics _objGraphics, PointF _objPointOne, PointF _objPointTwo,
  329. Color _objColor, int _intLineThickness)
  330. {
  331. using (Pen objPen = new Pen(new SolidBrush(_objColor), _intLineThickness))
  332. {
  333. objPen.StartCap = LineCap.Round;
  334. objPen.EndCap = LineCap.Round;
  335. _objGraphics.DrawLine(objPen, _objPointOne, _objPointTwo);
  336. }
  337. }
  338. private PointF GetCoordinate(PointF _objCircleCenter, int _intRadius, double _dblAngle)
  339. {
  340. double dblAngle = Math.PI * _dblAngle / NumberOfDegreesInHalfCircle;
  341. return new PointF(_objCircleCenter.X + _intRadius * (float)Math.Cos(dblAngle),
  342. _objCircleCenter.Y + _intRadius * (float)Math.Sin(dblAngle));
  343. }
  344. private void GetSpokesAngles()
  345. {
  346. m_Angles = GetSpokesAngles(NumberSpoke);
  347. }
  348. private double[] GetSpokesAngles(int _intNumberSpoke)
  349. {
  350. double[] Angles = new double[_intNumberSpoke];
  351. double dblAngle = (double)NumberOfDegreesInCircle / _intNumberSpoke;
  352. for (int shtCounter = 0; shtCounter < _intNumberSpoke; shtCounter++)
  353. Angles[shtCounter] = (shtCounter == 0 ? dblAngle : Angles[shtCounter - 1] + dblAngle);
  354. return Angles;
  355. }
  356. private void ActiveTimer()
  357. {
  358. if (m_IsTimerActive)
  359. m_Timer.Start();
  360. else
  361. {
  362. m_Timer.Stop();
  363. m_ProgressValue = 0;
  364. }
  365. GenerateColorsPallet();
  366. Invalidate();
  367. }
  368. #endregion
  369. #region 全局方法
  370. /// <summary>
  371. /// 获取适合控件区域的矩形大小。
  372. /// </summary>
  373. /// <param name="proposedSize">The custom-sized area for a control.</param>
  374. /// <returns>
  375. /// An ordered pair of type <see cref="T:System.Drawing.Size"></see> representing the width and height of a rectangle.
  376. /// </returns>
  377. public override Size GetPreferredSize(Size proposedSize)
  378. {
  379. proposedSize.Width =
  380. (m_OuterCircleRadius + m_SpokeThickness) * 2;
  381. return proposedSize;
  382. }
  383. /// <summary>
  384. /// 设置控件的外观
  385. /// </summary>
  386. /// <param name="numberSpoke">条数</param>
  387. /// <param name="spokeThickness">粗细</param>
  388. /// <param name="innerCircleRadius">内圆半径</param>
  389. /// <param name="outerCircleRadius">外圆半径</param>
  390. public void SetCircleAppearance(int numberSpoke, int spokeThickness,
  391. int innerCircleRadius, int outerCircleRadius)
  392. {
  393. NumberSpoke = numberSpoke;
  394. SpokeThickness = spokeThickness;
  395. InnerCircleRadius = innerCircleRadius;
  396. OuterCircleRadius = outerCircleRadius;
  397. Invalidate();
  398. }
  399. #endregion
  400. }
  401. }