/// <summary> /// 百分比控件 /// </summary> [ToolboxItem(true)] [DefaultProperty("Value")] [DefaultEvent("ValueChanged")] [Description("百分比控件")] public partial class PercentageBarExt : Control { public delegate void ValueEventHandler(object sender, ValueEventArgs e); #region private event ValueEventHandler valueChanged; /// <summary> /// 百分比值更改事件 /// </summary> [Description("百分比值更改事件")] public event ValueEventHandler ValueChanged { add { this.valueChanged += value; } remove { this.valueChanged -= value; } } private PercentageType type = PercentageType.Annulus; /// <summary> /// 百分比显示类型 /// </summary> [DefaultValue(PercentageType.Annulus)] [Description("百分比显示类型")] public PercentageType Type { get { return this.type; } set { if (this.type == value) return; this.type = value; this.Invalidate(); } } private int arcRadius = 50; /// <summary> /// 圆形半径 /// </summary> [DefaultValue(50)] [Description("圆形半径")] public int ArcRadius { get { return this.arcRadius; } set { if (this.arcRadius == value || value < 0) return; this.arcRadius = value; this.Invalidate(); } } private int arcAngle = 360; /// <summary> /// 圆弧弧度大小 /// </summary> [DefaultValue(360)] [Description("圆弧弧度大小")] public int ArcAngle { get { return this.arcAngle; } set { if (this.arcAngle == value || value < 0 || value > 360) return; this.arcAngle = value; this.Invalidate(); } } private int arcThickness = 10; /// <summary> /// 弧线大小 /// </summary> [DefaultValue(10)] [Description("弧线大小")] public int ArcThickness { get { return this.arcThickness; } set { if (this.arcThickness == value || value < 0 || value > this.ArcRadius) return; this.arcThickness = value; this.Invalidate(); } } private bool arcRound = false; /// <summary> /// 弧线是否为圆角 /// </summary> [DefaultValue(false)] [Description("弧线是否为圆角")] public bool ArcRound { get { return this.arcRound; } set { if (this.arcRound == value) return; this.arcRound = value; this.Invalidate(); } } private Color arcAnnulusBackColor = Color.Empty; /// <summary> /// 环形背景颜色(仅限于Annulus、Sector) /// </summary> [DefaultValue(typeof(Color), "Empty")] [Description("环形背景颜色(仅限于Annulus、Sector)")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color ArcAnnulusBackColor { get { return this.arcAnnulusBackColor; } set { if (this.arcAnnulusBackColor == value) return; this.arcAnnulusBackColor = value; this.Invalidate(); } } private Color arcBackColor = Color.FromArgb(112, 220, 220, 220); /// <summary> /// 弧线背景颜色 /// </summary> [DefaultValue(typeof(Color), "112, 220, 220, 220")] [Description("弧线背景颜色")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color ArcBackColor { get { return this.arcBackColor; } set { if (this.arcBackColor == value) return; this.arcBackColor = value; this.Invalidate(); } } private Color arcColor = Color.FromArgb(227, 240, 128, 128); /// <summary> /// 弧线颜色 /// </summary> [DefaultValue(typeof(Color), "227, 240, 128, 128")] [Description("弧线颜色")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color ArcColor { get { return this.arcColor; } set { if (this.arcColor == value) return; this.arcColor = value; this.Invalidate(); } } #region 方形 private int squareWidth = 10; /// <summary> /// 方形小格大小 /// </summary> [DefaultValue(10)] [Description("方形小格大小")] public int SquareWidth { get { return this.squareWidth; } set { if (this.squareWidth == value || value < 0) return; this.squareWidth = value; this.Invalidate(); } } private Color squareBorderColor = Color.FromArgb(149, 255, 255, 255); /// <summary> /// 方形小格边框颜色 /// </summary> [DefaultValue(typeof(Color), "149, 255, 255, 255")] [Description("方形小格边框颜色")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color SquareBorderColor { get { return this.squareBorderColor; } set { if (this.squareBorderColor == value) return; this.squareBorderColor = value; this.Invalidate(); } } #endregion private float value = 0f; /// <summary> /// 百分比值 /// </summary> [DefaultValue(0f)] [Description("百分比值")] public float Value { get { return this.value; } set { if (this.value == value || value < 0 || value > 1) return; this.value = value; if (this.valueChanged != null) { this.valueChanged(this, new ValueEventArgs() { Value = value }); } this.Invalidate(); } } private Font valueFont = new Font("宋体", 15); /// <summary> /// 百分比值字体 /// </summary> [DefaultValue(typeof(Font), "宋体, 15pt")] [Description("百分比值字体")] public Font ValueFont { get { return this.valueFont; } set { if (this.valueFont == value) return; this.valueFont = value; this.Invalidate(); } } private Color valueColor = Color.FromArgb(227, 255, 255, 255); /// <summary> /// 百分比值颜色 /// </summary> [DefaultValue(typeof(Color), "227, 255, 255, 255")] [Description("百分比值颜色")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color ValueColor { get { return this.valueColor; } set { if (this.valueColor == value) return; this.valueColor = value; this.Invalidate(); } } protected override Size DefaultSize { get { return new Size(100, 100); } } #endregion public PercentageBarExt() { SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.OptimizedDoubleBuffer, true); SetStyle(ControlStyles.ResizeRedraw, true); SetStyle(ControlStyles.SupportsTransparentBackColor, true); InitializeComponent(); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; Rectangle bounds_rect = new Rectangle((int)g.ClipBounds.X + ((int)g.ClipBounds.Width / 2 - this.ArcRadius) + 1, (int)g.ClipBounds.Y + ((int)g.ClipBounds.Height / 2 - this.ArcRadius) + 1, this.ArcRadius * 2 - 2, this.ArcRadius * 2 - 2); #region 环形 if (this.Type == PercentageType.Annulus) { #region 背景 Pen arcback_pen = new Pen(this.ArcBackColor, this.ArcThickness); g.DrawArc(arcback_pen, TransformRectangleF(bounds_rect, this.ArcThickness), 270, 360); arcback_pen.Dispose(); #endregion if (this.ArcAnnulusBackColor != Color.Empty) { SolidBrush arcannulusback_sb = new SolidBrush(this.ArcAnnulusBackColor); g.FillPie(arcannulusback_sb, bounds_rect.X + this.ArcThickness / 2, bounds_rect.Y + this.ArcThickness / 2, bounds_rect.Width - this.ArcThickness, bounds_rect.Height - this.ArcThickness, 270, 360); arcannulusback_sb.Dispose(); } #region 百分比值 Pen arc_pen = new Pen(this.ArcColor, this.ArcThickness); if (this.ArcRound) { arc_pen.StartCap = LineCap.Round; arc_pen.EndCap = LineCap.Round; } g.DrawArc(arc_pen, TransformRectangleF(bounds_rect, this.ArcThickness), 270, 360 * this.Value); arc_pen.Dispose(); #endregion #region 文本 this.DrawValueText(g, bounds_rect); #endregion } #endregion #region 扇形 else if (this.Type == PercentageType.Sector) { #region 背景 SolidBrush arcback_sb = new SolidBrush(this.ArcBackColor); g.FillPie(arcback_sb, bounds_rect.X, bounds_rect.Y, bounds_rect.Width, bounds_rect.Height, 270, 360); arcback_sb.Dispose(); #endregion if (this.ArcAnnulusBackColor != Color.Empty) { SolidBrush arcannulusback_sb = new SolidBrush(this.ArcAnnulusBackColor); g.FillPie(arcannulusback_sb, bounds_rect.X + this.ArcThickness / 2, bounds_rect.Y + this.ArcThickness / 2, bounds_rect.Width - this.ArcThickness, bounds_rect.Height - this.ArcThickness, 270, 360); arcannulusback_sb.Dispose(); } #region 百分比值 SolidBrush arc_sb = new SolidBrush(this.ArcColor); g.FillPie(arc_sb, bounds_rect.X, bounds_rect.Y, bounds_rect.Width, bounds_rect.Height, 270, 360 * this.Value); arc_sb.Dispose(); #endregion #region 文本 this.DrawValueText(g, bounds_rect); #endregion } #endregion #region 圆弧 else if (this.Type == PercentageType.Arc) { int start = this.ArcAngle == 360 ? 270 : 180 + (180 - this.ArcAngle) / 2; #region 背景 Pen arcback_pen = new Pen(this.ArcBackColor, this.ArcThickness); g.DrawArc(arcback_pen, TransformRectangleF(bounds_rect, this.ArcThickness), start, this.ArcAngle); arcback_pen.Dispose(); #endregion #region 百分比值 Pen arc_pen = new Pen(this.ArcColor, this.ArcThickness); if (this.ArcRound) { arc_pen.EndCap = LineCap.Round; } g.DrawArc(arc_pen, TransformRectangleF(bounds_rect, this.ArcThickness), start, this.ArcAngle * this.Value); arc_pen.Dispose(); #endregion #region 文本 this.DrawValueText(g, bounds_rect); #endregion } #endregion #region 方形 else if (this.Type == PercentageType.Square) { RectangleF rectf = new RectangleF(); rectf.Width = 11 + this.SquareWidth * 10; rectf.Height = 11 + this.SquareWidth * 10; rectf.X = g.ClipBounds.X + (g.ClipBounds.Width - rectf.Width) / 2; rectf.Y = g.ClipBounds.Bottom - rectf.Height; #region 背景 SolidBrush arcback_sb = new SolidBrush(this.ArcBackColor); g.FillRectangle(arcback_sb, rectf); arcback_sb.Dispose(); #endregion #region 百分比值 SolidBrush arc_sb = new SolidBrush(this.ArcColor); string str = this.Value.ToString("F4"); int index = str.IndexOf('.'); int row = int.Parse(str.Substring(index + 1, 1)); RectangleF row_rectf = new RectangleF(); row_rectf.Width = rectf.Width; row_rectf.Height = row * 1 + row * this.SquareWidth; row_rectf.X = rectf.X; row_rectf.Y = rectf.Bottom - row_rectf.Height; g.FillRectangle(arc_sb, row_rectf); int col = int.Parse(str.Substring(index + 2, 1)); if (col > 0) { RectangleF col_rectf = new RectangleF(); col_rectf.Width = col * 1 + col * this.SquareWidth; col_rectf.Height = this.SquareWidth + 1; col_rectf.X = rectf.X; col_rectf.Y = row_rectf.Y - col_rectf.Height; g.FillRectangle(arc_sb, col_rectf); } arc_sb.Dispose(); #endregion #region 边框 Pen arcbackborder_pen = new Pen(this.SquareBorderColor, 1); for (int i = 0; i < 11; i++)//行 { g.DrawLine(arcbackborder_pen, rectf.X, rectf.Y + i * 1 + i * this.SquareWidth, rectf.Right, rectf.Y + i * 1 + i * this.SquareWidth); } for (int i = 0; i < 11; i++)//列 { g.DrawLine(arcbackborder_pen, rectf.X + i * 1 + i * this.SquareWidth, rectf.Y, rectf.X + i * 1 + i * this.SquareWidth, rectf.Bottom); } arcbackborder_pen.Dispose(); #endregion #region 百分比值文本 string value_str = (this.Value * 100).ToString("F0") + "%"; StringFormat value_sf = new StringFormat(); value_sf.FormatFlags = StringFormatFlags.NoWrap; value_sf.Alignment = StringAlignment.Center; value_sf.Trimming = StringTrimming.None; Size value_size = g.MeasureString(value_str, this.ValueFont, new Size(), value_sf).ToSize(); SolidBrush value_sb = new SolidBrush(this.ValueColor); g.DrawString(value_str, this.ValueFont, value_sb, new RectangleF(rectf.X + (rectf.Width - value_size.Width) / 2, rectf.Y - value_size.Height, value_size.Width, value_size.Height), value_sf); value_sb.Dispose(); value_sf.Dispose(); #endregion } #endregion #region 条形 else if (this.Type == PercentageType.Bar) { RectangleF rectf = new RectangleF(); rectf.Width = g.ClipBounds.Width - (this.ArcRound ? this.ArcThickness : 0); rectf.Height = this.ArcThickness; rectf.X = g.ClipBounds.X + (this.ArcRound ? this.ArcThickness / 2 : 0); rectf.Y = g.ClipBounds.Bottom - rectf.Height; #region 背景 Pen arcback_pen = new Pen(this.ArcBackColor, this.ArcThickness); if (this.ArcRound) { arcback_pen.StartCap = LineCap.Round; arcback_pen.EndCap = LineCap.Round; } g.DrawLine(arcback_pen, rectf.X, rectf.Bottom - rectf.Height / 2, rectf.Right, rectf.Bottom - rectf.Height / 2); arcback_pen.Dispose(); #endregion #region 百分比值 Pen arc_pen = new Pen(this.ArcColor, this.ArcThickness); if (this.ArcRound) { arc_pen.StartCap = LineCap.Round; arc_pen.EndCap = LineCap.Round; } g.DrawLine(arc_pen, rectf.X, rectf.Bottom - rectf.Height / 2, (int)(rectf.Right * this.Value), rectf.Bottom - rectf.Height / 2); arc_pen.Dispose(); #endregion #region 百分比值文本 string value_str = (this.Value * 100).ToString("F0") + "%"; StringFormat value_sf = new StringFormat(); value_sf.FormatFlags = StringFormatFlags.NoWrap; value_sf.Alignment = StringAlignment.Center; value_sf.Trimming = StringTrimming.None; Size value_size = g.MeasureString(value_str, this.ValueFont, new Size(), value_sf).ToSize(); SolidBrush value_sb = new SolidBrush(this.ValueColor); g.DrawString(value_str, this.ValueFont, value_sb, new RectangleF(rectf.X + (rectf.Width - value_size.Width) / 2, rectf.Y - value_size.Height, value_size.Width, value_size.Height), value_sf); value_sb.Dispose(); value_sf.Dispose(); #endregion } #endregion } /// <summary> /// 绘制百分值文本 /// </summary> /// <param name="g"></param> /// <param name="rect"></param> private void DrawValueText(Graphics g, RectangleF rectf) { string value_str = (this.Value * 100).ToString("F0") + "%"; StringFormat value_sf = new StringFormat(); value_sf.FormatFlags = StringFormatFlags.NoWrap; value_sf.Alignment = StringAlignment.Center; value_sf.Trimming = StringTrimming.None; Size value_size = g.MeasureString(value_str, this.ValueFont, new Size(), value_sf).ToSize(); SolidBrush value_sb = new SolidBrush(this.ValueColor); g.DrawString(value_str, this.ValueFont, value_sb, new RectangleF(rectf.X + (rectf.Width - value_size.Width) / 2, rectf.Y + (rectf.Height - value_size.Height) / 2, value_size.Width, value_size.Height), value_sf); value_sb.Dispose(); value_sf.Dispose(); } /// <summary> /// 根据画笔大小转换rectf /// </summary> /// <param name="rectf">要转换的rectf</param> /// <param name="pen">画笔大小大小</param> /// <returns></returns> private static RectangleF TransformRectangleF(RectangleF rectf, int pen) { RectangleF result = new RectangleF(); result.Width = rectf.Width - (pen < 1 ? 0 : pen); result.Height = rectf.Height - (pen < 1 ? 0 : pen); result.X = rectf.X + (float)(pen / 2); result.Y = rectf.Y + (float)(pen / 2); return result; } protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } /// <summary> /// 百分比值更改事件参数 /// </summary> [Description("百分比值更改事件参数")] public class ValueEventArgs : EventArgs { /// <summary> /// 百分比值 /// </summary> [Description("百分比值")] public float Value { get; set; } } /// <summary> /// 百分比显示类型 /// </summary> [Description("百分比显示类型")] public enum PercentageType { /// <summary> /// 环形 /// </summary> Annulus, /// <summary> /// 圆弧 /// </summary> Arc, /// <summary> /// 扇形 /// </summary> Sector, /// <summary> /// 方形 /// </summary> Square, /// <summary> /// 条形 /// </summary> Bar } }
源码下载:百分比控件.zip