GDI+编程(2)---等待控件

[Serializable, StructLayout(LayoutKind.Sequential), TypeConverter(typeof(CircleFConverter))]
    public sealed class CircleF : ICloneable
    {
        public static CircleF Empty = new CircleF();
        PointF _pivot;//圆心
        float _radius;//半径
        public CircleF() : this(default(PointF), 0)
        {

        }
        public CircleF(RectangleF rectf)
        {
            _pivot = GetCirclePivot(rectf);
            _radius = GetCircleRadius(rectf);
        }

        public CircleF(PointF pivot, float radius)
        {
            _pivot = pivot;
            _radius = radius;
        }
        public static PointF GetCirclePivot(RectangleF rect)
        {
            return new PointF(rect.X + rect.Width / 2.0f, rect.Y + rect.Height / 2.0f);
        }
        public static float GetCircleRadius(RectangleF rect)
        {
            return Math.Min(rect.Width / 2.0f, rect.Height / 2.0f);
        }
        [TypeConverter(typeof(ExpandableObjectConverter))]
        public PointF Pivot { get { return _pivot; } set { _pivot = value; } }
        public float Radius
        {
            get { return _radius; }
            set
            {
                if (value >= 0)
                    _radius = value;
            }
        }
        public RectangleF GetBounds()
        {
            return new RectangleF(_pivot.X - _radius, _pivot.Y - _radius, _radius * 2.0f, _radius * 2.0f);
        }
        public static RectangleF GetBounds(RectangleF rect)
        {
            PointF p = GetCirclePivot(rect);
            float d = GetCircleRadius(rect);
            return new RectangleF(p.X - d, p.Y - d, d * 2.0f, d * 2.0f);
        }
        public bool Contains(float x, float y)
        {
            return Contains(new PointF(x, y));
        }

        public bool Contains(PointF p)
        {
            return Distance(p) <= _radius;
        }

        public float Distance(CircleF c)
        {
            return Distance(c.Pivot);
        }
        public float Distance(PointF p)
        {
            return (float)Math.Sqrt((p.X - _pivot.X) * (p.X - _pivot.X) + (p.Y - _pivot.Y) * (p.Y - _pivot.Y));
        }
        public object Clone()
        {
            return this.MemberwiseClone();
        }
        public PointF PointOnPath(double sweepAngle)
        {
            return new PointF(_pivot.X + _radius * (float)Math.Cos(sweepAngle * (Math.PI / 180.0d)), _pivot.Y - _radius * (float)Math.Sin(sweepAngle * (Math.PI / 180.0d)));
        }
        public void Offset(float x, float y)
        {
            _pivot.X += x;
            _pivot.Y += y;
        }
        public void Offset(System.Drawing.PointF pos)
        {
            Offset(pos.X, pos.Y);
        }

        public void Inflate(float d)
        {
            Radius += d;
        }
        public static bool operator !=(CircleF left, CircleF right)
        {
            return left._pivot == right._pivot && left._radius == right._radius;
        }
        public static bool operator ==(CircleF left, CircleF right)
        {
            return !(left != right);
        }
        public override string ToString()
        {
            return string.Format("{{Pivot={0},Radius={1}}}", _pivot, _radius);
        }
        public static implicit operator RectangleF(CircleF c)
        {
            return c.GetBounds();
        }
    }
    public class CircleFConverter : TypeConverter
    {
        public CircleFConverter()
        {

        }
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(string))
                return true;
            return base.CanConvertTo(context, destinationType);
        }

        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (value is CircleF)
            {
                if (destinationType == typeof(string))
                {
                    CircleF c = value as CircleF;
                    return string.Format("({0},{1}),{2}", c.Pivot.X, c.Pivot.Y, c.Radius);
                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }

        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
                return true;
            else
                return base.CanConvertFrom(context, sourceType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value is string)
            {
                string[] ti = ((string)value).Split(',');
                float x = float.Parse(ti[0].Substring(1));
                float y = float.Parse(ti[1].Substring(0, ti[1].Length - 1));
                float r = float.Parse(ti[2]);
                return new CircleF(new PointF(x, y), r);
            }
            return base.ConvertFrom(context, culture, value);
        }

        public override PropertyDescriptorCollection? GetProperties(ITypeDescriptorContext? context, object value, Attribute[]? attributes)
        {
            return TypeDescriptor.GetProperties(typeof(CircleF), attributes).Sort(new string[] { "Radius", "Pivot" });
        }
        public override bool GetPropertiesSupported(ITypeDescriptorContext? context)
        {
            return true;
        }
    }
/// <summary>
    /// 封装生成高级衍生图形的各种静态方法/// </summary>
    public static class ExtendedShapes
    {
        public static PointF[] CreateRegularPolygon(PointF pivot, float outterRadius, int points, float angleOffset)
        {
            if (outterRadius < 0) throw new ArgumentOutOfRangeException("outterRadius", "多边形的外接圆半径必须大于0");

            if (points < 3) throw new ArgumentOutOfRangeException("points", "多边形的边数必须大于等于3");
            PointF[] ret = new PointF[points];
            CircleF c = new CircleF(pivot, outterRadius); float ang = 360.0f / points;
            for (int i = 0; i < points; i++)
            {
                ret[i] = c.PointOnPath(angleOffset + i * ang);
            }
            return ret;
        }
        public static PointF[] CreateRegularPolygon(PointF pivot, float outterRadius, int points)
        {
            return CreateRegularPolygon(pivot, outterRadius, points, 0.0f);
        }
        public static GraphicsPath CreateStar(PointF pivot, float outterRadius, float innerRadius, int points, float angleOffset)
        {
            if (outterRadius <= innerRadius) throw new ArgumentException("参数 outterRadius必须大于innerRadius。");
            if (points < 2) throw new ArgumentOutOfRangeException("points"); GraphicsPath gp = new GraphicsPath();
            CircleF outter = new CircleF(pivot, outterRadius);
            CircleF inner = new CircleF(pivot, innerRadius); float ang = 360.0f / points;
            for (int i = 0; i < points; i++)
            {
                gp.AddLine(outter.PointOnPath(angleOffset + i * ang), inner.PointOnPath(angleOffset + i * ang + ang / 2.0f));
            }

            gp.CloseFigure();
            return gp;
        }

        public static GraphicsPath CreateStar(PointF pivot, float outterRadius, float innerRadius, int points)
        {
            return CreateStar(pivot, outterRadius, innerRadius, points, 0);
        }
        public static GraphicsPath CreateChamferBox(RectangleF rect, float radius)
        {
            GraphicsPath gp = new GraphicsPath();
            if (radius <= 0) { gp.AddRectangle(rect); return gp; }
            gp.AddArc(rect.Right - 2 * radius, rect.Top, radius * 2, radius * 2, 270, 90);
            gp.AddArc(rect.Right - radius * 2, rect.Bottom - radius * 2, radius * 2, radius * 2, 0, 90);
            gp.AddArc(rect.Left, rect.Bottom - 2 * radius, 2 * radius, 2 * radius, 90, 90);
            gp.AddArc(rect.Left, rect.Top, 2 * radius, 2 * radius, 180, 90); gp.CloseFigure();
            return gp;
        }
        public static List<PointF[]> CreateWaitCircleSpokes(PointF pivot, float outterRadius, float innerRadius, int spokes, float angleOffset)
        {
            if (spokes < 1) throw new ArgumentException("参数spokes必须大于等于。"); List<PointF[]> lst = new List<PointF[]>();
            CircleF outter = new CircleF(pivot, outterRadius); CircleF inner = new CircleF(pivot, innerRadius);
            float ang = 360.0f / spokes;
            for (int i = 0; i < spokes; i++)
                lst.Add(new PointF[2] { outter.PointOnPath(angleOffset + i * ang), inner.PointOnPath(angleOffset + i * ang) });
            return lst;
        }

        public static List<PointF[]> CreateWaitCircleSpokes(PointF pivot, float outterRadius, float innerRadius, int spokes)
        {
            return CreateWaitCircleSpokes(pivot, outterRadius, innerRadius, spokes,
            0.0f);
        }
    }

 

public class WaitingControl : Control
    {
        private int _numberofspokes = 20; //控件包含的总的辐条数量 
        private int _hotspokes = 5; //活动辐条数 
        private float _innerRadius; //内环半径,外环半径根据控件的大小计算 
        private Color _spokeColor = Color.LightGray;//辐条颜色
        private Color _hotSpokeColor = Color.Gray; //活动辐条颜色
        private int _thickness = 3; //辐条的宽度 
        private bool _antialias = true; //控件绘制时是否反走样 
        private bool _colockWise = true; //活动辐条是否顺时针旋转
        private List<PointF[]> _spokes; //辐条轮廓线列表 
        protected Color[] _palette; //渐变色调色板 
        private System.Windows.Forms.Timer _timer; //计时器 
        private Pen _pen; //绘制WaitingCircle的画笔 
        private int _offset = 0; //活动辐条偏移量
        public WaitingControl()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
            _timer = new System.Windows.Forms.Timer();
            _timer.Tick += _timer_Tick; ;
            _pen = new Pen(_spokeColor, _thickness);
            this.Text = "请稍等";
            this.Size = new Size(120, 120);
            GeneratePalette();
        }

        private void _timer_Tick(object? sender, EventArgs e)
        {
            Invalidate();
            _offset = ((_colockWise ? --_offset : ++_offset) + _numberofspokes) % _numberofspokes;
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            CircleF c = new CircleF(ClientRectangle); c.Inflate(-5.0f);
            _innerRadius = c.Radius / 2.0f;
            _spokes = ExtendedShapes.CreateWaitCircleSpokes(c.Pivot, c.Radius, _innerRadius, _numberofspokes);
        }
        public float InnerRadius
        {
            get { return _innerRadius; }
            set
            {
                if (_innerRadius != value && value > 0)
                    _innerRadius = value;
                CircleF c = new CircleF(ClientRectangle);
                c.Inflate(-5.0f);
                _spokes = ExtendedShapes.CreateWaitCircleSpokes(c.Pivot, c.Radius, _innerRadius, _numberofspokes); 
                Invalidate();
            }
        }

        public int NumberOfSpokes
        {
            get { return _numberofspokes; }
            set
            {
                _numberofspokes = Math.Max(2, Math.Max(_hotspokes, value)); CircleF c = new CircleF(ClientRectangle);
                c.Inflate(-5.0f);
                _spokes = ExtendedShapes.CreateWaitCircleSpokes(c.Pivot, c.Radius, _innerRadius, _numberofspokes);
                Invalidate();
            }
        }
        public LineCap StartCap
        {
            get { return _pen.StartCap; }
            set
            {
                _pen.StartCap = value; Invalidate();
            }
        }

        public LineCap EndCap
        {
            get { return _pen.EndCap; }
            set { _pen.EndCap = value; Invalidate(); }
        }
        public int Thickness
        {
            get { return _thickness; }
            set
            {
                if (value > 0)
                    _thickness = value; _pen.Width = _thickness; Invalidate();
            }
        }
        protected virtual void GeneratePalette()
        {
            _palette = new Color[_hotspokes];
            float a = (float)(_hotSpokeColor.A - _spokeColor.A) / (float)_hotspokes;
            float r = (float)(_hotSpokeColor.R - _spokeColor.R) / (float)_hotspokes;
            float g = (float)(_hotSpokeColor.G - _spokeColor.G) / (float)_hotspokes;
            float b = (float)(_hotSpokeColor.B - _spokeColor.B) / (float)_hotspokes;
            for (int i = 0; i < _hotspokes; i++)
            {
                _palette[i] = Color.FromArgb(_hotSpokeColor.A - (int)(i * a),
                _hotSpokeColor.R - (int)(i * r), _hotSpokeColor.G - (int)(i * g), _hotSpokeColor.B - (int)(i * b));
            }
        }
        public int Speed
        {
            get { return _timer.Interval; }
            set { _timer.Interval = value; }
        }
        public bool Activate
        {
            get { return _timer.Enabled; }
            set { _timer.Enabled = value; this.Invalidate(); }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            DrawSpokes(e.Graphics);
        }
        protected void DrawSpokes(Graphics g)
        {
            g.SmoothingMode = _antialias ? SmoothingMode.AntiAlias : SmoothingMode.Default;
            if (!Activate)
            {
                _pen.Color = _spokeColor;
                foreach (PointF[] spoke in _spokes)
                {
                    g.DrawLines(_pen, spoke);
                }
            }
            else
            {
                List<int> hot = new List<int>(); //存储活动辐条的索引 
                for (int i = 0; i < _hotspokes; i++) //计算活动辐条的索引 
                {
                    int index = ((_colockWise ? _offset - i : _offset + i) + _numberofspokes) % _numberofspokes; 
                    hot.Add(index);
                }
                _pen.Color = _spokeColor;
                for (int i = 0; i < _numberofspokes; i++)//首先绘制非活动辐条
                {
                    if (!hot.Contains(i))
                    {
                       
                        g.DrawLines(_pen, _spokes[i]);
                    }
                }
                for (int i = 0; i < _hotspokes; i++) //绘制活动辐条 
                {
                    _pen.Color = _palette[_hotspokes - 1 - i];
                    g.DrawLines(_pen, _spokes[hot[i]]);
                }
            }
            if (!string.IsNullOrWhiteSpace(this.Text))
            {
                SizeF sf = this.Text.MeasureString(this.Font);
                using SolidBrush solid=new SolidBrush(this.ForeColor);
                g.DrawString(this.Text, this.Font, solid, new PointF((this.Width-sf.Width)/2,(this.Height-sf.Height)/2));
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            if (disposing)
            {
                _pen.Dispose();
                _timer?.Dispose();
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值