2025-03-28 09:49:56 +08:00

245 lines
6.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using ThreadingTimer = System.Threading.Timer;
using UITimer = System.Windows.Forms.Timer;
namespace InvoicingTool
{
/// <summary>
/// 表示一个加载圆圈动画
/// </summary>
[ToolboxBitmap(typeof(LoadingCircle), "LoadingCircleIcon.png")]
public partial class LoadingCircle : UserControl
{
#region
public LoadingCircle()
{
InitializeComponent();
//双缓冲,禁擦背景
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer,
true);
//初始化绘图timer
_graphicsTmr = new UITimer { Interval = 1 };
//Invalidate()强制重绘,绘图操作在OnPaint中实现
_graphicsTmr.Tick += (sender1, e1) => Invalidate(false);
_dotSize = Width / 10f;
//初始化"点"
DotCount = 5;
_dots = new Dot[DotCount];
Color = Color.White;
}
#endregion
#region
/// <summary>
/// 圆心
/// </summary>
[Browsable(false)]
public PointF CircleCenter
{
get { return new PointF(Width / 2f, Height / 2f); }
}
/// <summary>
/// 半径
/// </summary>
[Browsable(false)]
public float CircleRadius
{
get { return Width / 2f - _dotSize; }
}
/// <summary>
/// 颜色
/// </summary>
[Browsable(true), Category("Appearance"), Description("设置\"点\"的前景色")]
public Color Color { get; set; }
/// <summary>
/// 数量
/// </summary>
[Browsable(true),Category("Appearance"),Description("设置\"点\"的数量\n有效值1-10"),DefaultValue(5)]
public UInt32 DotCount { get; set; }
#endregion
#region
//点数组
private Dot[] _dots;
//Timers
private readonly UITimer _graphicsTmr;
private ThreadingTimer _actionTmr;
//点大小
private float _dotSize;
//是否活动
private bool _isActived;
//是否绘制:用于状态重置时挂起与恢复绘图
private bool _isDrawing = true;
//Timer计数:用于延迟启动每个点
private int _timerCount;
#endregion
#region
//动作间隔(Timer)
private const int ActionInterval = 30;
//计数基数用于计算每个点启动延迟index * timerCountRadix
private const int TimerCountRadix = 45;
#endregion
#region
//检查是否重置
private bool CheckToReset()
{
return _dots.Count(d => d.Opacity > 0) == 0;
}
//初始化点元素
private void CreateDots()
{
if (DotCount < 1 || DotCount > 10)
DotCount = 5;
_dots = new Dot[DotCount];
for (int i = 0; i < _dots.Length; ++i)
_dots[i] = new Dot(CircleCenter, CircleRadius);
}
/// <summary>
/// 开关
/// </summary>
public bool Switch()
{
if (!_isActived)
Start();
else
Stop();
return _isActived;
}
/// <summary>
/// 开始
/// </summary>
public void Start()
{
CreateDots();
_timerCount = 0;
foreach (Dot dot in _dots)
dot.Reset();
_graphicsTmr.Start();
//初始化动作timer
_actionTmr = new ThreadingTimer(
state =>
{
//动画动作
for (int i = 0; i < _dots.Length; i++)
if (_timerCount++ > i * TimerCountRadix)
_dots[i].DotAction();
//是否重置
if (CheckToReset())
{
//重置前暂停绘图
_isDrawing = false;
_timerCount = 0;
foreach (Dot dot in _dots)
dot.Reset();
//恢复绘图
_isDrawing = true;
}
_actionTmr.Change(ActionInterval, Timeout.Infinite);
},
null, ActionInterval, Timeout.Infinite);
_isActived = true;
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
_graphicsTmr.Stop();
_actionTmr.Dispose();
_isActived = false;
}
#endregion
#region
protected override void OnPaint(PaintEventArgs e)
{
if (_isActived && _isDrawing)
{
//抗锯齿
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
using (var bmp = new Bitmap(200, 200))
{
//缓冲绘制
using (Graphics bufferGraphics = Graphics.FromImage(bmp))
{
//抗锯齿
bufferGraphics.SmoothingMode = SmoothingMode.HighQuality;
foreach (Dot dot in _dots)
{
var rect = new RectangleF(
new PointF(dot.Location.X - _dotSize / 2, dot.Location.Y - _dotSize / 2),
new SizeF(_dotSize, _dotSize));
bufferGraphics.FillEllipse(new SolidBrush(Color.FromArgb(dot.Opacity, Color)),
rect);
}
}
//贴图
e.Graphics.DrawImage(bmp, new PointF(0, 0));
} //bmp disposed
}
base.OnPaint(e);
}
protected override void OnResize(EventArgs e)
{
Height = Width;
_dotSize = Width / 12f;
base.OnResize(e);
}
#endregion
}
}