/// <summary> /// 多点滑块进度控件 /// </summary> [ToolboxItem(true)] [DefaultProperty("Items")] [DefaultEvent("SlideValueChanged")] [Description("多点滑块进度控件")] public partial class SlideBarExt : Control { public delegate void EventHandler(object sender, SlideValueEventArgs e); #region private event EventHandler slideValueChanged; /// <summary> /// 滑块选项值更改事件 /// </summary> [Description("滑块选项值更改事件")] public event EventHandler SlideValueChanged { add { this.slideValueChanged += value; } remove { this.slideValueChanged -= value; } } private SlideOrientation orientation = SlideOrientation.HorizontalBottom; /// <summary> /// 控件滑块方向位置 /// </summary> [DefaultValue(SlideOrientation.HorizontalBottom)] [Description("控件滑块方向位置")] public SlideOrientation Orientation { get { return this.orientation; } set { if (this.orientation == value) return; this.orientation = value; this.InitializeSlideValueRectangleFs(); this.Invalidate(); } } private int slidePadding = 6; /// <summary> /// 控件边距 /// </summary> [DefaultValue(6)] [Description("控件边距")] public int SlidePadding { get { return this.slidePadding; } set { if (this.slidePadding == value || value < 0) return; this.slidePadding = value; this.InitializeSlideValueRectangleFs(); this.Invalidate(); } } private float maxValue = 100f; /// <summary> /// 最大值 /// </summary> [DefaultValue(100f)] [Description("最大值")] public float MaxValue { get { return this.maxValue; } set { if (this.maxValue == value || value < this.minValue) return; this.maxValue = value; this.Invalidate(); } } private float minValue = 0f; /// <summary> /// 最小值 /// </summary> [DefaultValue(0f)] [Description("最小值")] public float MinValue { get { return this.minValue; } set { if (this.minValue == value || value > this.maxValue) return; this.minValue = value; this.Invalidate(); } } #region 背景 private Color backdropColor = Color.FromArgb(76, 240, 128, 128); /// <summary> /// 背景颜色 /// </summary> [DefaultValue(typeof(Color), "76, 240, 128, 128")] [Description("背景颜色")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color BackdropColor { get { return this.backdropColor; } set { if (this.backdropColor == value) return; this.backdropColor = value; this.Invalidate(); } } private int backdropThickness = 8; /// <summary> /// 背景大小 /// </summary> [DefaultValue(8)] [Description("背景大小")] public int BackdropThickness { get { return this.backdropThickness; } set { if (this.backdropThickness == value || value < 0) return; this.backdropThickness = value; this.Invalidate(); } } private bool backdropRadius = true; /// <summary> /// 背景是否为圆角 /// </summary> [DefaultValue(true)] [Description("背景是否为圆角")] public bool BackdropRadius { get { return this.backdropRadius; } set { if (this.backdropRadius == value) return; this.backdropRadius = value; this.Invalidate(); } } #endregion #region 滑块 private int slideWidth = 20; /// <summary> /// 滑块宽度 /// </summary> [DefaultValue(20)] [Description("滑块宽度")] public int SlideWidth { get { return this.slideWidth; } set { if (this.slideWidth == value || value < 0) return; this.slideWidth = value; this.InitializeSlideValueRectangleFs(); this.Invalidate(); } } private int slideHeight = 20; /// <summary> /// 滑块高度 /// </summary> [DefaultValue(20)] [Description("滑块高度")] public int SlideHeight { get { return this.slideHeight; } set { if (this.slideHeight == value || value < 0) return; this.slideHeight = value; this.InitializeSlideValueRectangleFs(); this.Invalidate(); } } private int slideRadius = 10; /// <summary> /// 滑块圆角大小(限于Flat) /// </summary> [DefaultValue(10)] [Description("滑块圆角大小(限于Flat)")] public int SlideRadius { get { return this.slideRadius; } set { if (this.slideRadius == value || value < 0) return; this.slideRadius = value; this.InitializeSlideValueRectangleFs(); this.Invalidate(); } } private Color slideColor = Color.FromArgb(255, 128, 128); /// <summary> /// 滑块颜色(总体设置) /// </summary> [DefaultValue(typeof(Color), "255, 128, 128")] [Description("滑块颜色(总体设置)")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color SlideColor { get { return this.slideColor; } set { if (this.slideColor == value) return; this.slideColor = value; this.Invalidate(); } } private Color slideProgressColor = Color.FromArgb(175, 240, 128, 128); /// <summary> /// 滑块进度颜色(仅限于只有一个滑块) /// </summary> [DefaultValue(typeof(Color), "175, 240, 128, 128")] [Description("滑块进度颜色(仅限于只有一个滑块)")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color SlideProgressColor { get { return this.slideProgressColor; } set { if (this.slideProgressColor == value) return; this.slideProgressColor = value; this.Invalidate(); } } private int selectIndex = -1; /// <summary> /// 当前选中滑块的索引 /// </summary> [Browsable(false)] [DefaultValue(-1)] [Description("当前选中滑块的索引")] public int SelectIndex { get { return this.selectIndex; } } private SlideValueCollection slideValueCollection; /// <summary> /// 滑块选项集合 /// </summary> [DefaultValue(null)] [Description("滑块选项集合")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public SlideValueCollection Items { get { if (this.slideValueCollection == null) this.slideValueCollection = new SlideValueCollection(this); return this.slideValueCollection; } } #endregion #region 提示信息 private bool tipShow = true; /// <summary> /// 是否显示提示信息 /// </summary> [DefaultValue(true)] [Description("是否显示提示信息")] public bool TipShow { get { return this.tipShow; } set { if (this.tipShow == value) return; this.tipShow = value; this.Invalidate(); } } private Color tipBackdropColor = Color.FromArgb(126, 255, 128, 128); /// <summary> /// 提示信息背景颜色 /// </summary> [DefaultValue(typeof(Color), "126, 255, 128, 128")] [Description("提示信息背景颜色")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color TipBackdropColor { get { return this.tipBackdropColor; } set { if (this.tipBackdropColor == value) return; this.tipBackdropColor = value; this.Invalidate(); } } private Font tipFont = new Font("宋体", 11, FontStyle.Regular); /// <summary> /// 提示信息字体 /// </summary> [DefaultValue(typeof(Font), "11pt style=Regular")] [Description("提示信息字体")] public Font TipFont { get { return this.tipFont; } set { if (this.tipFont == value) return; this.tipFont = value; this.Invalidate(); } } private Color tipColor = Color.FromArgb(150, 255, 255, 255); /// <summary> /// 提示信息颜色 /// </summary> [DefaultValue(typeof(Color), "150,255, 255, 255")] [Description("提示信息颜色")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color TipColor { get { return this.tipColor; } set { if (this.tipColor == value) return; this.tipColor = value; this.Invalidate(); } } #endregion protected override Size DefaultSize { get { return new Size(300, 60); } } /// <summary> /// 鼠标状态 /// </summary> private MoveStatus move_status = MoveStatus.Leave; /// <summary> /// 鼠标坐标 /// </summary> private Point move_point; #endregion public SlideBarExt() { 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 rectf = new Rectangle(this.SlidePadding, this.SlidePadding, e.ClipRectangle.Width - this.SlidePadding * 2, e.ClipRectangle.Height - this.SlidePadding * 2); #region 背景 Pen backdrop_pen = new Pen(this.BackdropColor, this.BackdropThickness); int backdrop_x_start = 0; int backdrop_x_end = 0; int backdrop_y = 0; if (this.Orientation == SlideOrientation.HorizontalTop || this.Orientation == SlideOrientation.HorizontalBottom) { backdrop_x_start = rectf.X; backdrop_x_end = rectf.Right; backdrop_y = (this.Orientation == SlideOrientation.HorizontalTop) ? this.SlidePadding + this.SlideHeight / 2 : rectf.Bottom - this.SlideHeight / 2 - this.SlidePadding; if (this.BackdropRadius) { backdrop_pen.StartCap = LineCap.Round; backdrop_pen.EndCap = LineCap.Round; backdrop_x_start += this.BackdropThickness / 2; backdrop_x_end -= this.BackdropThickness / 2; } g.DrawLine(backdrop_pen, backdrop_x_start, backdrop_y, backdrop_x_end, backdrop_y); } else { backdrop_x_start = rectf.Y; backdrop_x_end = rectf.Bottom; backdrop_y = (this.Orientation == SlideOrientation.VerticalLeft) ? this.SlidePadding + this.SlideWidth / 2 : rectf.Right - this.SlideWidth / 2 - this.SlidePadding; if (this.BackdropRadius) { backdrop_pen.StartCap = LineCap.Round; backdrop_pen.EndCap = LineCap.Round; backdrop_x_start += this.BackdropThickness / 2; backdrop_x_end -= this.BackdropThickness / 2; } g.DrawLine(backdrop_pen, backdrop_y, backdrop_x_start, backdrop_y, backdrop_x_end); } backdrop_pen.Dispose(); #endregion #region 进度值 if (this.Orientation == SlideOrientation.HorizontalTop || this.Orientation == SlideOrientation.HorizontalBottom) { if (this.Items.Count == 1) { int slideProgress_x_start = rectf.X; int slideProgress_x_end = (int)(this.Items[0].RectF.Right - this.Items[0].RectF.Width) + this.SlideWidth / 2; int slideProgress_y = (this.Orientation == SlideOrientation.HorizontalTop) ? this.SlidePadding + this.SlideHeight / 2 : rectf.Bottom - this.SlideHeight / 2 - this.SlidePadding; Pen slideProgress_pen = new Pen(this.SlideProgressColor, this.BackdropThickness); if (this.BackdropRadius) { slideProgress_pen.StartCap = LineCap.Round; slideProgress_x_start += this.BackdropThickness / 2; } g.DrawLine(slideProgress_pen, slideProgress_x_start, slideProgress_y, slideProgress_x_end, slideProgress_y); slideProgress_pen.Dispose(); } } else { if (this.Items.Count == 1) { int slideProgress_x_start = rectf.Bottom; int slideProgress_x_end = (int)(this.Items[0].RectF.Bottom - this.Items[0].RectF.Height); int slideProgress_y = (this.Orientation == SlideOrientation.VerticalLeft) ? this.SlidePadding + this.SlideWidth / 2 : rectf.Right - this.SlideWidth / 2 - this.SlidePadding; Pen slideProgress_pen = new Pen(this.SlideProgressColor, this.BackdropThickness); if (this.BackdropRadius) { slideProgress_pen.StartCap = LineCap.Round; slideProgress_x_start -= this.BackdropThickness / 2; } g.DrawLine(slideProgress_pen, slideProgress_y, slideProgress_x_start, slideProgress_y, slideProgress_x_end); slideProgress_pen.Dispose(); } } #endregion #region 滑块 int line_area = 6;//连线区域大小 Pen tooltipline_pen = new Pen(this.TipBackdropColor, 2); SolidBrush tooltipback_sb = new SolidBrush(this.TipBackdropColor); for (int i = 0; i < this.Items.Count; i++) { #region 滑块 SolidBrush slide_sb = new SolidBrush(this.Items[i].SlideColor == Color.Empty ? this.SlideColor : this.Items[i].SlideColor); GraphicsPath slide_gp = TransformCircular(new RectangleF(this.Items[i].RectF.X, this.Items[i].RectF.Y, this.Items[i].RectF.Width, this.Items[i].RectF.Height), this.SlideRadius); g.FillPath(slide_sb, slide_gp); slide_gp.Dispose(); slide_sb.Dispose(); #endregion #region 计算提示信息的位置 if (this.TipShow) { string tooltiptext_str = this.Items[i].Value.ToString("F2"); Size tooltiptext_size = TextRenderer.MeasureText(tooltiptext_str, this.TipFont, new Size(), TextFormatFlags.NoPadding | TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter); Rectangle tooltipback_rect = new Rectangle(0, 0, tooltiptext_size.Width, tooltiptext_size.Height); if (this.Orientation == SlideOrientation.HorizontalTop) { tooltipback_rect.X = (int)this.Items[i].RectF.X + ((int)this.Items[i].RectF.Width - tooltipback_rect.Width) / 2; if (tooltipback_rect.X < 0) tooltipback_rect.X = 0; tooltipback_rect.Y = (int)this.Items[i].RectF.Bottom + line_area; if (i > 0 && (tooltipback_rect.X < this.Items[i - 1].TipRect.Right + line_area)) { tooltipback_rect.X = (int)this.Items[i - 1].TipRect.Right + line_area; } } else if (this.Orientation == SlideOrientation.HorizontalBottom) { tooltipback_rect.X = (int)this.Items[i].RectF.X + ((int)this.Items[i].RectF.Width - tooltipback_rect.Width) / 2; if (tooltipback_rect.X < 0) tooltipback_rect.X = 0; tooltipback_rect.Y = (int)this.Items[i].RectF.Y - line_area - tooltipback_rect.Height; if (i > 0 && (tooltipback_rect.X < this.Items[i - 1].TipRect.Right + line_area)) { tooltipback_rect.X = (int)this.Items[i - 1].TipRect.Right + line_area; } } else if (this.Orientation == SlideOrientation.VerticalLeft) { tooltipback_rect.X = (int)this.Items[i].RectF.Right + line_area; tooltipback_rect.Y = (int)this.Items[i].RectF.Y + ((int)this.Items[i].RectF.Height - tooltipback_rect.Height) / 2; if (tooltipback_rect.Y > rectf.Bottom - tooltipback_rect.Height) tooltipback_rect.Y = rectf.Bottom - tooltipback_rect.Height; if (i > 0 && (tooltipback_rect.Y > (int)this.Items[i - 1].TipRect.Y - line_area - tooltipback_rect.Height)) { tooltipback_rect.Y = (int)this.Items[i - 1].TipRect.Y - line_area - tooltipback_rect.Height; } } else if (this.Orientation == SlideOrientation.VerticalRight) { tooltipback_rect.X = (int)this.Items[i].RectF.X - line_area - tooltipback_rect.Width; tooltipback_rect.Y = (int)this.Items[i].RectF.Y + ((int)this.Items[i].RectF.Height - tooltipback_rect.Height) / 2; if (tooltipback_rect.Y > rectf.Bottom - tooltipback_rect.Height) tooltipback_rect.Y = rectf.Bottom - tooltipback_rect.Height; if (i > 0 && (tooltipback_rect.Y > (int)this.Items[i - 1].TipRect.Y - line_area - tooltipback_rect.Height)) { tooltipback_rect.Y = (int)this.Items[i - 1].TipRect.Y - line_area - tooltipback_rect.Height; } } this.Items[i].TipRect = tooltipback_rect; } #endregion } #region if (this.TipShow) { for (int i = this.Items.Count - 1; i >= 0; i--) { if (this.Orientation == SlideOrientation.HorizontalTop || this.Orientation == SlideOrientation.HorizontalBottom) { if ((i == this.Items.Count - 1)) { if (this.Items[i].TipRect.Right > rectf.Right) this.Items[i].TipRect = new Rectangle((int)(rectf.Right - this.Items[i].TipRect.Width), this.Items[i].TipRect.Y, this.Items[i].TipRect.Width, this.Items[i].TipRect.Height); } else { if (this.Items[i].TipRect.Right + line_area > this.Items[i + 1].TipRect.X) this.Items[i].TipRect = new Rectangle((this.Items[i + 1].TipRect.X - this.Items[i].TipRect.Width - line_area), this.Items[i].TipRect.Y, this.Items[i].TipRect.Width, this.Items[i].TipRect.Height); } this.Items[i].Slidepoint = new PointF(this.Items[i].RectF.X + this.Items[i].RectF.Width / 2, this.Items[i].RectF.Bottom); this.Items[i].Tippoint = new PointF(this.Items[i].TipRect.X + this.Items[i].TipRect.Width / 2, this.Items[i].TipRect.Y); if (this.Orientation == SlideOrientation.HorizontalBottom) { this.Items[i].Slidepoint = new PointF(this.Items[i].RectF.X + this.Items[i].RectF.Width / 2, this.Items[i].RectF.Y); this.Items[i].Tippoint = new PointF(this.Items[i].TipRect.X + this.Items[i].TipRect.Width / 2, this.Items[i].TipRect.Bottom); } } else if (this.Orientation == SlideOrientation.VerticalLeft || this.Orientation == SlideOrientation.VerticalRight) { if (i == this.Items.Count - 1) { if (this.Items[i].TipRect.Y < rectf.Y) this.Items[i].TipRect = new Rectangle(this.Items[i].TipRect.X, rectf.Y, this.Items[i].TipRect.Width, this.Items[i].TipRect.Height); } else { if (this.Items[i].TipRect.Y < this.Items[i + 1].TipRect.Bottom + line_area) this.Items[i].TipRect = new Rectangle(this.Items[i].TipRect.X, this.Items[i + 1].TipRect.Bottom + line_area, this.Items[i].TipRect.Width, this.Items[i].TipRect.Height); } this.Items[i].Slidepoint = new PointF(this.Items[i].RectF.Right, this.Items[i].RectF.Bottom - this.Items[i].RectF.Height / 2); this.Items[i].Tippoint = new PointF(this.Items[i].TipRect.Left, this.Items[i].TipRect.Bottom - this.Items[i].TipRect.Height / 2); if (this.Orientation == SlideOrientation.VerticalRight) { this.Items[i].Slidepoint = new PointF(this.Items[i].RectF.X, this.Items[i].RectF.Bottom - this.Items[i].RectF.Height / 2); this.Items[i].Tippoint = new PointF(this.Items[i].TipRect.Right, this.Items[i].TipRect.Bottom - this.Items[i].TipRect.Height / 2); } } g.DrawLine(tooltipline_pen, this.Items[i].Slidepoint, this.Items[i].Tippoint); g.FillRectangle(tooltipback_sb, this.Items[i].TipRect); string tooltiptext_str = this.Items[i].Value.ToString("F2"); TextRenderer.DrawText(g, tooltiptext_str, this.TipFont, this.Items[i].TipRect, this.TipColor, TextFormatFlags.NoPadding | TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter); } } #endregion tooltipback_sb.Dispose(); tooltipline_pen.Dispose(); #endregion } protected override void OnResize(EventArgs e) { base.OnResize(e); this.InitializeSlideValueRectangleFs(); } protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); this.move_status = MoveStatus.Down; Point point = this.PointToClient(Control.MousePosition); this.move_point = point; this.selectIndex = this.GetSelectSlideIndex(point); } protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); this.move_status = MoveStatus.Up; this.selectIndex = -1; } protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); this.move_status = MoveStatus.Enter; } protected override void OnMouseLeave(EventArgs e) { base.OnMouseLeave(e); this.move_status = MoveStatus.Leave; this.selectIndex = -1; } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (this.move_status == MoveStatus.Down) { if (this.SelectIndex > -1) { this.InitializeSlideValue(this.Items[this.SelectIndex]); } } else { Point point = this.PointToClient(Control.MousePosition); this.Cursor = (this.GetSelectSlideIndex(point) > -1) ? Cursors.Hand : Cursors.Default; } } #region /// <summary> /// 根据当前鼠标坐标计算滑块值 /// </summary> /// <param name="item">当前滑块</param> private void InitializeSlideValue(SlideValue item) { Rectangle rect = new Rectangle(this.SlidePadding, this.SlidePadding, this.ClientRectangle.Width - this.SlidePadding * 2, this.ClientRectangle.Height - this.SlidePadding * 2); Point point = this.PointToClient(Control.MousePosition); if (this.Orientation == SlideOrientation.HorizontalTop || this.Orientation == SlideOrientation.HorizontalBottom) { if (point.X == this.move_point.X) return; int index = this.Items.IndexOf(item); float value_l = Math.Abs(this.MinValue) + Math.Abs(this.MaxValue);//值总长度 float back_l = rect.Width - this.SlideWidth - (this.Items.Count - 1) * this.SlideWidth;//背景总长度 float increment = value_l / back_l;//一个像素代表曾值量 float value = item.Value; value += increment * (point.X - this.move_point.X); this.move_point = point; item.Value = value; } else { if (point.Y == this.move_point.Y) return; int index = this.Items.IndexOf(item); float value_l = Math.Abs(this.MinValue) + Math.Abs(this.MaxValue);//值总长度 float back_l = rect.Height - this.SlideHeight - (this.Items.Count - 1) * this.SlideHeight;//背景总长度 float increment = value_l / back_l;//一个像素代表曾值量 float value = item.Value; value -= increment * (point.Y - this.move_point.Y); this.move_point = point; item.Value = value; } } /// <summary> /// 计算所有滑块rectf /// </summary> /// <param name="item"></param> private void InitializeSlideValueRectangleFs() { for (int i = 0; i < this.Items.Count; i++) { this.InitializeSlideValueRectangleF(this.Items[i]); } } /// <summary> /// 计算指定滑块rectf /// </summary> /// <param name="item"></param> private void InitializeSlideValueRectangleF(SlideValue item) { Rectangle rect = new Rectangle(this.SlidePadding, this.SlidePadding, this.ClientRectangle.Width - this.SlidePadding * 2, this.ClientRectangle.Height - this.SlidePadding * 2); int index = this.Items.IndexOf(item); if (this.Orientation == SlideOrientation.HorizontalBottom || this.Orientation == SlideOrientation.HorizontalTop) { float back_l = rect.Width - this.SlideWidth - (this.Items.Count - 1) * this.SlideWidth; int slide_x = this.SlidePadding + (this.SlideWidth / 2) + (int)(item.Value / (Math.Abs(this.MinValue) + Math.Abs(this.MaxValue)) * back_l); if (slide_x < 0) slide_x = 0; if (slide_x > rect.Right - this.SlideWidth / 2) slide_x = rect.Right - this.SlideWidth / 2; int slide_y = (this.Orientation == SlideOrientation.HorizontalTop) ? rect.Y : rect.Bottom - this.SlideHeight - this.SlidePadding; item.RectF = new RectangleF(slide_x - (this.SlideWidth / 2) + index * this.SlideWidth, slide_y, this.SlideWidth, this.SlideHeight); } else { float back_l = rect.Height - this.SlideHeight - (this.Items.Count - 1) * this.SlideHeight; int slide_y = rect.Bottom - (this.SlideHeight / 2) - (int)(item.Value / (Math.Abs(this.MinValue) + Math.Abs(this.MaxValue)) * back_l); if (slide_y < 0) slide_y = 0; if (slide_y > rect.Bottom - this.SlideHeight / 2) slide_y = rect.Bottom - this.SlideHeight / 2; int slide_x = (this.Orientation == SlideOrientation.VerticalLeft) ? rect.X : rect.Right - this.SlideWidth - this.SlidePadding; item.RectF = new RectangleF(slide_x, slide_y - (this.SlideHeight / 2) - index * this.SlideHeight, this.SlideWidth, this.SlideHeight); } } /// <summary> /// 获取选中滑块索引 /// </summary> /// <param name="point">当前鼠标坐标</param> /// <returns></returns> private int GetSelectSlideIndex(Point point) { for (int i = 0; i < this.Items.Count; i++) { if (this.Items[i].RectF.Contains(point)) return i; } return -1; } /// <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; } /// <summary> /// 转换成圆角 /// </summary> /// <param name="rectf">要转换的rectf</param> /// <param name="radius">圆角半径的大小</param> /// <returns></returns> private static GraphicsPath TransformCircular(RectangleF rectf, int radius = 0) { return TransformCircular(rectf, radius, radius, radius, radius); } /// <summary> /// 转换成圆角 /// </summary> /// <param name="rectf">要转换的rectf</param> /// <param name="leftTopRadius">左上角</param> /// <param name="rightTopRadius">右上角</param> /// <param name="rightBottomRadius">右下角</param> /// <param name="leftBottomRadius">左下角</param> /// <returns></returns> private static GraphicsPath TransformCircular(RectangleF rectf, int leftTopRadius = 0, int rightTopRadius = 0, int rightBottomRadius = 0, int leftBottomRadius = 0) { GraphicsPath gp = new GraphicsPath(); if (leftTopRadius > 0) { RectangleF lefttop_rect = new RectangleF(rectf.X, rectf.Y, leftTopRadius * 2, leftTopRadius * 2); gp.AddArc(lefttop_rect, 180, 90); } else { gp.AddLine(new PointF(rectf.X, rectf.Y), new PointF(rightTopRadius > 0 ? rectf.Right - rightTopRadius * 2 : rectf.Right, rectf.Y)); } if (rightTopRadius > 0) { RectangleF righttop_rect = new RectangleF(rectf.Right - rightTopRadius * 2, rectf.Y, rightTopRadius * 2, rightTopRadius * 2); gp.AddArc(righttop_rect, 270, 90); } else { gp.AddLine(new PointF(rectf.Right, rectf.Y), new PointF(rectf.Right, rightBottomRadius > 0 ? rectf.Bottom - rightTopRadius * 2 : rectf.Bottom)); } if (rightBottomRadius > 0) { RectangleF rightbottom_rect = new RectangleF(rectf.Right - rightTopRadius * 2, rectf.Bottom - rightTopRadius * 2, rightBottomRadius * 2, rightBottomRadius * 2); gp.AddArc(rightbottom_rect, 0, 90); } else { gp.AddLine(new PointF(rectf.Right, rectf.Bottom), new PointF(leftBottomRadius > 0 ? leftBottomRadius * 2 : rectf.X, rectf.Bottom)); } if (leftBottomRadius > 0) { RectangleF rightbottom_rect = new RectangleF(rectf.X, rectf.Bottom - leftBottomRadius * 2, leftBottomRadius * 2, leftBottomRadius * 2); gp.AddArc(rightbottom_rect, 90, 90); } else { gp.AddLine(new PointF(rectf.X, rectf.Bottom), new PointF(rectf.X, leftTopRadius > 0 ? rectf.X + leftTopRadius * 2 : rectf.X)); } gp.CloseAllFigures(); return gp; } #endregion protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } /// <summary> /// 滑块选项集合 /// </summary> [Description("滑块选项集合")] [Editor(typeof(CollectionEditorExt), typeof(UITypeEditor))] public sealed class SlideValueCollection : IList, ICollection, IEnumerable { private ArrayList slideValueList = new ArrayList(); private SlideBarExt owner; public SlideValueCollection(SlideBarExt owner) { this.owner = owner; } #region IEnumerable public IEnumerator GetEnumerator() { SlideValue[] listArray = new SlideValue[this.slideValueList.Count]; for (int index = 0; index < listArray.Length; ++index) listArray[index] = (SlideValue)this.slideValueList[index]; return listArray.GetEnumerator(); } #endregion #region ICollection public void CopyTo(Array array, int index) { for (int i = 0; i < this.Count; i++) array.SetValue(this.slideValueList[i], i + index); } public int Count { get { return this.slideValueList.Count; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return (object)this; } } #endregion #region IList public int Add(object value) { SlideValue slideValue = (SlideValue)value; slideValue.owner = this.owner; slideValue.self = slideValue; this.slideValueList.Add(slideValue); this.owner.InitializeSlideValueRectangleF(slideValue); this.owner.Invalidate(); return this.Count - 1; } public void Clear() { this.slideValueList.Clear(); this.owner.Invalidate(); } public bool Contains(object value) { return this.IndexOf(value) != -1; } public int IndexOf(object value) { return this.slideValueList.IndexOf(value); } public void Insert(int index, object value) { throw new NotImplementedException(); } public bool IsFixedSize { get { return false; } } public bool IsReadOnly { get { return false; } } public void Remove(object value) { if (!(value is SlideValue)) return; this.slideValueList.Remove((SlideValue)value); this.owner.Invalidate(); } public void RemoveAt(int index) { this.slideValueList.RemoveAt(index); this.owner.Invalidate(); } public SlideValue this[int index] { get { return (SlideValue)this.slideValueList[index]; } set { this.slideValueList[index] = (SlideValue)value; this.owner.InitializeSlideValueRectangleF((SlideValue)value); this.owner.Invalidate(); } } object IList.this[int index] { get { return (object)this.slideValueList[index]; } set { this.slideValueList[index] = (SlideValue)value; this.owner.InitializeSlideValueRectangleF((SlideValue)value); this.owner.Invalidate(); } } #endregion } /// <summary> /// 滑块选项 /// </summary> [Description("滑块选项")] public class SlideValue { public SlideValue() { } public SlideValue(SlideBarExt owner) { this.owner = owner; } /// <summary> /// 控件主体 /// </summary> public SlideBarExt owner; /// <summary> /// 当前滑块选项 /// </summary> public SlideValue self; private RectangleF rectf = new RectangleF(); /// <summary> /// 滑块rectf /// </summary> [Browsable(false)] [Description("滑块rectf")] public RectangleF RectF { get { return this.rectf; } set { if (this.rectf == value) return; this.rectf = value; } } private Rectangle tiprect = new Rectangle(); /// <summary> /// 滑块提示信息rect /// </summary> [Browsable(false)] [Description("滑块提示信息rect")] public Rectangle TipRect { get { return this.tiprect; } set { if (this.tiprect == value) return; this.tiprect = value; } } private PointF slidepoint = new Point(); /// <summary> /// 连线滑块的坐标 /// </summary> [Browsable(false)] [Description("连线滑块的坐标")] public PointF Slidepoint { get { return this.slidepoint; } set { if (this.slidepoint == value) return; this.slidepoint = value; } } private PointF tippoint = new Point(); /// <summary> /// 连线提示信息的坐标 /// </summary> [Browsable(false)] [Description("连线提示信息的坐标")] public PointF Tippoint { get { return this.tippoint; } set { if (this.tippoint == value) return; this.tippoint = value; } } private float value { get; set; } /// <summary> /// 滑块值 /// </summary> [Browsable(true)] [DefaultValue("0f")] [Description("滑块值")] public float Value { get { return this.value; } set { if (this.value == value) return; if (this.owner != null) { if (value < this.owner.MinValue) value = this.owner.MinValue; if (value > this.owner.MaxValue) value = this.owner.MaxValue; int index = this.owner.Items.IndexOf(self); if (this.owner.Items.Count > 1) { if (value > this.value)//往右移动 { if (index < this.owner.Items.Count - 1) { if (value > this.owner.Items[index + 1].Value) { value = this.owner.Items[index + 1].Value; } } } else if (value < this.value) { if (index > 0) { if (value < this.owner.Items[index - 1].Value) { value = this.owner.Items[index - 1].Value; } } } } this.value = value; this.owner.InitializeSlideValueRectangleF(self); this.owner.Invalidate(); if (this.owner.slideValueChanged != null) { this.owner.slideValueChanged(this.owner, new SlideValueEventArgs() { Item = self }); } } } } private Color slideColor = Color.Empty; /// <summary> /// 滑块颜色 /// </summary> [Browsable(true)] [DefaultValue(typeof(Color), "Empty")] [Description("滑块颜色")] [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))] public Color SlideColor { get { return this.slideColor; } set { if (this.slideColor == value) return; this.slideColor = value; if (this.owner != null) { this.owner.Invalidate(); } } } } /// <summary> /// 滑块选项值更改事件参数 /// </summary> [Description("滑块选项值更改事件参数")] public class SlideValueEventArgs : EventArgs { /// <summary> /// 滑块选项 /// </summary> [Description("滑块选项")] public SlideValue Item { get; set; } } /// <summary> /// 鼠标状态 /// </summary> [Description("鼠标状态")] private enum MoveStatus { /// <summary> /// 鼠标进入 /// </summary> Enter, /// <summary> /// 鼠标离开 /// </summary> Leave, /// <summary> /// 鼠标按下 /// </summary> Down, /// <summary> /// 鼠标按下释放 /// </summary> Up } /// <summary> /// 控件滑块方向位置 /// </summary> [Description("控件滑块方向位置")] public enum SlideOrientation { /// <summary> ///水平放置靠近上边 /// </summary> HorizontalTop, /// <summary> /// 水平放置靠近下边 /// </summary> HorizontalBottom, /// <summary> /// 垂直放置靠近左边 /// </summary> VerticalLeft, /// <summary> /// 垂直放置靠近右边 /// </summary> VerticalRight, } }
源码下载:多点滑块进度控件.zip
原文地址:https://www.cnblogs.com/tlmbem/p/11410163.html
时间: 2024-10-16 00:03:10