using System; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Windows.Forms; using System.Windows.Forms; namespace Mesnac.Controls.ChemicalWeighing { /// 一个简单的管道线控件,只能横竖两种模式,支持流动动画显示 [Description("管道流动控件,支持横竖模式,支持显示流动动画,多个控件组合使用出更高级的效果")] public class HslPipeLine : UserControl { private HslDirectionStyle hslPipeLineStyle = HslDirectionStyle.Horizontal; private Color centerColor = Color.LightGray; private Color edgeColor = Color.DimGray; private Pen edgePen = new Pen(Color.DimGray, 1f); private HslPipeTurnDirection hslPipeTurnLeft = HslPipeTurnDirection.None; private HslPipeTurnDirection hslPipeTurnRight = HslPipeTurnDirection.None; private bool isPipeLineActive = false; private int pipeLineWidth = 1; private Color colorPipeLineCenter = Color.DodgerBlue; private float moveSpeed = 0.0f; private float startOffect = 0.0f; private Timer timer = (Timer)null; private float antLength = 5f; /// 必需的设计器变量。 private IContainer components = (IContainer)null; /// 实例化一个默认的管道线对象 public HslPipeLine() { this.InitializeComponent(); this.SetStyle(ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor, true); this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.timer = new Timer(); this.timer.Interval = 50; this.timer.Tick += new EventHandler(this.Timer_Tick); this.timer.Start(); } /// protected override void OnLoad(EventArgs e) { base.OnLoad(e); this.SizeChanged += new EventHandler(this.HslPipeLine_SizeChanged); this.BackgroundImage = (Image)this.getBackgroundImg(this.Width, this.Height); } private void HslPipeLine_SizeChanged(object sender, EventArgs e) { this.BackgroundImage?.Dispose(); this.BackgroundImage = (Image)this.getBackgroundImg(this.Width, this.Height); } /// protected override void OnPaint(PaintEventArgs e) { e.Graphics.SmoothingMode = SmoothingMode.HighQuality; e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; this.PaintHslControls(e.Graphics, this.Width, this.Height); base.OnPaint(e); } /// public void PaintHslControls(Graphics g, int width, int height) { this.PaintMain(g, this.Width, this.Height); } private Bitmap getBackgroundImg(int width, int height) { Bitmap backgroundImg = new Bitmap(width, height); Graphics g = Graphics.FromImage((Image)backgroundImg); g.SmoothingMode = SmoothingMode.AntiAlias; g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; ColorBlend colorBlend = new ColorBlend(); colorBlend.Positions = new float[3] { 0.0f, 0.5f, 1f }; colorBlend.Colors = new Color[3] { this.edgeColor, this.centerColor, this.edgeColor }; if (this.hslPipeLineStyle == HslDirectionStyle.Horizontal) { LinearGradientBrush linearGradientBrush = new LinearGradientBrush(new Point(0, 0), new Point(0, this.Height - 1), this.edgeColor, this.centerColor); linearGradientBrush.InterpolationColors = colorBlend; if (this.hslPipeTurnLeft == HslPipeTurnDirection.Up) this.PaintEllipse(g, colorBlend, new Rectangle(0, -this.Height - 1, 2 * this.Height, 2 * this.Height), 90f, 90f); else if (this.hslPipeTurnLeft == HslPipeTurnDirection.Down) this.PaintEllipse(g, colorBlend, new Rectangle(0, 0, 2 * this.Height, 2 * this.Height), 180f, 90f); else this.PaintRectangleBorderUpDown(g, (Brush)linearGradientBrush, this.edgePen, new Rectangle(0, 0, this.Height, this.Height)); if (this.hslPipeTurnRight == HslPipeTurnDirection.Up) this.PaintEllipse(g, colorBlend, new Rectangle(this.Width - 1 - this.Height * 2, -this.Height - 1, 2 * this.Height, 2 * this.Height), 0.0f, 90f); else if (this.hslPipeTurnRight == HslPipeTurnDirection.Down) this.PaintEllipse(g, colorBlend, new Rectangle(this.Width - 1 - this.Height * 2, 0, 2 * this.Height, 2 * this.Height), 270f, 90f); else this.PaintRectangleBorderUpDown(g, (Brush)linearGradientBrush, this.edgePen, new Rectangle(this.Width - this.Height, 0, this.Height, this.Height)); if (this.Width - this.Height * 2 >= 0) this.PaintRectangleBorderUpDown(g, (Brush)linearGradientBrush, this.edgePen, new Rectangle(this.Height - 1, 0, this.Width - 2 * this.Height + 2, this.Height)); linearGradientBrush.Dispose(); } else { LinearGradientBrush linearGradientBrush = new LinearGradientBrush(new Point(0, 0), new Point(this.Width - 1, 0), this.edgeColor, this.centerColor); linearGradientBrush.InterpolationColors = colorBlend; if (this.hslPipeTurnLeft == HslPipeTurnDirection.Left) this.PaintEllipse(g, colorBlend, new Rectangle(-this.Width - 1, 0, 2 * this.Width, 2 * this.Width), 270f, 90f); else if (this.hslPipeTurnLeft == HslPipeTurnDirection.Right) this.PaintEllipse(g, colorBlend, new Rectangle(0, 0, 2 * this.Width, 2 * this.Width), 180f, 90f); else this.PaintRectangleBorderLeftRight(g, (Brush)linearGradientBrush, this.edgePen, new Rectangle(0, 0, this.Width, this.Width)); if (this.hslPipeTurnRight == HslPipeTurnDirection.Left) this.PaintEllipse(g, colorBlend, new Rectangle(-this.Width - 1, this.Height - this.Width * 2, 2 * this.Width, 2 * this.Width), 0.0f, 90f); else if (this.hslPipeTurnRight == HslPipeTurnDirection.Right) this.PaintEllipse(g, colorBlend, new Rectangle(0, this.Height - this.Width * 2, 2 * this.Width, 2 * this.Width), 90f, 90f); else this.PaintRectangleBorderLeftRight(g, (Brush)linearGradientBrush, this.edgePen, new Rectangle(0, this.Height - this.Width, this.Width, this.Width)); if (this.Height - this.Width * 2 >= 0) this.PaintRectangleBorderLeftRight(g, (Brush)linearGradientBrush, this.edgePen, new Rectangle(0, this.Width - 1, this.Width, this.Height - this.Width * 2 + 2)); linearGradientBrush.Dispose(); } return backgroundImg; } private void PaintMain(Graphics g, int width, int height) { GraphicsPath path = new GraphicsPath(FillMode.Alternate); if (this.hslPipeLineStyle == HslDirectionStyle.Horizontal) { if (this.isPipeLineActive) { if (this.Width < this.Height) { path.AddLine(0, this.Height / 2, this.Height, this.Height / 2); } else { if (this.hslPipeTurnLeft == HslPipeTurnDirection.Up) path.AddArc(new Rectangle(this.Height / 2, -this.Height / 2 - 1, this.Height, this.Height), 180f, -90f); else if (this.hslPipeTurnLeft == HslPipeTurnDirection.Down) path.AddArc(new Rectangle(this.Height / 2, this.Height / 2, this.Height, this.Height), 180f, 90f); else path.AddLine(0, this.Height / 2, this.Height, this.Height / 2); if (this.Width - this.Height * 2 >= 0) path.AddLine(this.Height, this.Height / 2, this.Width - this.Height - 1, this.Height / 2); if (this.hslPipeTurnRight == HslPipeTurnDirection.Up) path.AddArc(new Rectangle(this.Width - 1 - this.Height * 3 / 2, -this.Height / 2 - 1, this.Height, this.Height), 90f, -90f); else if (this.hslPipeTurnRight == HslPipeTurnDirection.Down) path.AddArc(new Rectangle(this.Width - 1 - this.Height * 3 / 2, this.Height / 2, this.Height, this.Height), 270f, 90f); else path.AddLine(this.Width - this.Height, this.Height / 2, this.Width - 1, this.Height / 2); } } } else if (this.isPipeLineActive) { if (this.Width > this.Height) { path.AddLine(0, this.Height / 2, this.Height, this.Height / 2); } else { if (this.hslPipeTurnLeft == HslPipeTurnDirection.Left) path.AddArc(new Rectangle(-this.Width / 2, this.Width / 2 - 1, this.Width, this.Width), 270f, 90f); else if (this.hslPipeTurnLeft == HslPipeTurnDirection.Right) path.AddArc(new Rectangle(this.Width / 2, this.Width / 2 - 1, this.Width, this.Width), 270f, -90f); else path.AddLine(this.Width / 2, 0, this.Width / 2, this.Width); if (this.Height - this.Width * 2 >= 0) path.AddLine(this.Width / 2, this.Width, this.Width / 2, this.Height - this.Width - 1); if (this.hslPipeTurnRight == HslPipeTurnDirection.Left) path.AddArc(new Rectangle(-this.Width / 2, this.Height - 1 - this.Width * 3 / 2, this.Width, this.Width), 0.0f, 90f); else if (this.hslPipeTurnRight == HslPipeTurnDirection.Right) path.AddArc(new Rectangle(this.Width / 2, this.Height - 1 - this.Width * 3 / 2, this.Width, this.Width), -180f, -90f); else path.AddLine(this.Width / 2, this.Height - this.Width, this.Width / 2, this.Height - 1); } } using (Pen pen = new Pen(this.colorPipeLineCenter, (float)this.pipeLineWidth)) { pen.DashStyle = DashStyle.Custom; pen.DashPattern = new float[2] { this.antLength, this.antLength }; pen.DashOffset = this.startOffect; g.DrawPath(pen, path); } path.Dispose(); } private void PaintEllipse( Graphics g, ColorBlend colorBlend, Rectangle rect, float startAngle, float sweepAngle) { GraphicsPath path = new GraphicsPath(); path.AddEllipse(rect); PathGradientBrush pathGradientBrush = new PathGradientBrush(path); pathGradientBrush.CenterPoint = (PointF)new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2); pathGradientBrush.InterpolationColors = colorBlend; g.FillPie((Brush)pathGradientBrush, rect, startAngle, sweepAngle); g.DrawArc(this.edgePen, rect, startAngle, sweepAngle); pathGradientBrush.Dispose(); path.Dispose(); } private void PaintRectangleBorder( Graphics g, Brush brush, Pen pen, Rectangle rectangle, bool left, bool right, bool up, bool down) { g.FillRectangle(brush, rectangle); if (left) g.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Y + rectangle.Height - 1); if (up) g.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X + rectangle.Width - 1, rectangle.Y); if (right) g.DrawLine(pen, rectangle.X + rectangle.Width - 1, rectangle.Y, rectangle.X + rectangle.Width - 1, rectangle.Y + rectangle.Height - 1); if (!down) return; g.DrawLine(pen, rectangle.X, rectangle.Y + rectangle.Height - 1, rectangle.X + rectangle.Width - 1, rectangle.Y + rectangle.Height - 1); } private void PaintRectangleBorderLeftRight( Graphics g, Brush brush, Pen pen, Rectangle rectangle) { this.PaintRectangleBorder(g, brush, pen, rectangle, true, true, false, false); } private void PaintRectangleBorderUpDown(Graphics g, Brush brush, Pen pen, Rectangle rectangle) => this.PaintRectangleBorder(g, brush, pen, rectangle, false, false, true, true); private void PaintRectangleBorder(Graphics g, Brush brush, Pen pen, Rectangle rectangle) => this.PaintRectangleBorder(g, brush, pen, rectangle, true, true, true, true); private void Timer_Tick(object sender, EventArgs e) { if (!this.isPipeLineActive || (double)this.moveSpeed == 0.0) return; this.startOffect -= this.moveSpeed; if ((double)this.startOffect <= -((double)this.antLength * 2.0) || (double)this.startOffect >= (double)this.antLength * 2.0) this.startOffect = 0.0f; this.Invalidate(); } private void Timer_Tick2(object status) { if (!this.isPipeLineActive) return; this.startOffect -= this.moveSpeed; if ((double)this.startOffect <= -10.0 || (double)this.startOffect >= 10.0) this.startOffect = 0.0f; Bitmap bitmap = new Bitmap(this.Width, this.Height); Graphics g = Graphics.FromImage((Image)bitmap); g.SmoothingMode = SmoothingMode.HighQuality; g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; this.PaintMain(g, this.Width, this.Height); g.Dispose(); if (this.InvokeRequired) { //this.Invoke((m => //{ // this.BackgroundImage?.Dispose(); // this.BackgroundImage = (Image)bitmap; //}), (object)bitmap); this.Invoke(new EventHandler(delegate (Object sd, EventArgs ag) { this.BackgroundImage?.Dispose(); this.BackgroundImage = (Image)bitmap; }), (object)bitmap); } else { this.BackgroundImage?.Dispose(); this.BackgroundImage = (Image)bitmap; } } private void Invoke(System.Action value) { throw new NotImplementedException(); } /// 获取或设置控件的背景色 [Browsable(true)] [Description("获取或设置控件的背景色")] [Category("HslControls")] [DefaultValue(typeof(Color), "Transparent")] [EditorBrowsable(EditorBrowsableState.Always)] public override Color BackColor { get => base.BackColor; set => base.BackColor = value; } /// 获取或设置管道控件的边缘颜色 [Browsable(true)] [Description("获取或设置管道控件的边缘颜色")] [Category("HslControls")] [DefaultValue(typeof(Color), "DimGray")] public Color EdgeColor { get => this.edgeColor; set { this.edgeColor = value; this.edgePen.Dispose(); this.edgePen = new Pen(value, 1f); this.Invalidate(); this.HslPipeLine_SizeChanged((object)this, new EventArgs()); } } /// 获取或设置管道控件的中心颜色 [Browsable(true)] [Description("获取或设置管道控件的中心颜色")] [Category("HslControls")] [DefaultValue(typeof(Color), "LightGray")] public Color LineCenterColor { get => this.centerColor; set { this.centerColor = value; this.Invalidate(); this.HslPipeLine_SizeChanged((object)this, new EventArgs()); } } /// 获取或设置管道控件左侧或是上方的端点朝向 [Browsable(true)] [Description("获取或设置管道控件左侧或是上方的端点朝向")] [Category("HslControls")] [DefaultValue(typeof(HslPipeTurnDirection), "None")] public HslPipeTurnDirection PipeTurnLeft { get => this.hslPipeTurnLeft; set { this.hslPipeTurnLeft = value; this.HslPipeLine_SizeChanged((object)null, (EventArgs)null); this.Invalidate(); } } /// 获取或设置管道控件右侧或是下方的端点朝向 [Browsable(true)] [Description("获取或设置管道控件左侧或是上方的端点朝向")] [Category("HslControls")] [DefaultValue(typeof(HslPipeTurnDirection), "None")] public HslPipeTurnDirection PipeTurnRight { get => this.hslPipeTurnRight; set { this.hslPipeTurnRight = value; this.HslPipeLine_SizeChanged((object)null, (EventArgs)null); this.Invalidate(); } } /// 获取或设置管道控件是否是横向的还是纵向的 [Browsable(true)] [Description("获取或设置管道控件是否是横向的还是纵向的")] [Category("HslControls")] [DefaultValue(typeof(HslDirectionStyle), "Vertical")] public HslDirectionStyle PipeLineStyle { get => this.hslPipeLineStyle; set { this.hslPipeLineStyle = value; this.Invalidate(); } } /// 获取或设置管道线是否激活液体显示 [Browsable(true)] [Description("获取或设置管道线是否激活液体显示")] [Category("HslControls")] [DefaultValue(false)] public bool PipeLineActive { get => this.isPipeLineActive; set { this.isPipeLineActive = value; this.Invalidate(); } } /// 获取或设置管道线液体流动的速度,0为静止,正数为正向流动,负数为反向流动 [Browsable(true)] [Description("获取或设置管道线液体流动的速度,0为静止,正数为正向流动,负数为反向流动")] [Category("HslControls")] [DefaultValue(0.0f)] public float MoveSpeed { get => this.moveSpeed; set { this.moveSpeed = value; this.Invalidate(); } } /// 获取或设置液体控制的定时器刷新的间隔,默认是50 [Browsable(true)] [Description("获取或设置液体控制的定时器刷新的间隔,默认是50")] [Category("HslControls")] [DefaultValue(50)] public int TimerInterval { get => this.timer.Interval; set => this.timer.Interval = value; } /// 获取或设置中间管道线的宽度信息,默认为1 [Browsable(true)] [Description("获取或设置中间管道线的宽度信息,默认为1")] [Category("HslControls")] [DefaultValue(1)] public int PipeLineWidth { get => this.pipeLineWidth; set { this.pipeLineWidth = value; this.Invalidate(); } } /// 获取或设置流动状态时管道控件的中心颜色 [Browsable(true)] [Description("获取或设置流动状态时管道控件的中心颜色")] [Category("HslControls")] [DefaultValue(typeof(Color), "DodgerBlue")] public Color ActiveLineCenterColor { get => this.colorPipeLineCenter; set { this.colorPipeLineCenter = value; this.Invalidate(); } } /// 获取或设置蚂蚁线的长度信息 [Browsable(true)] [Description("获取或设置蚂蚁线的长度信息")] [Category("HslControls")] [DefaultValue(5f)] public float AntLength { get => this.antLength; set { this.antLength = value; this.Invalidate(); } } /// 清理所有正在使用的资源。 /// 如果应释放托管资源,为 true;否则为 false。 protected override void Dispose(bool disposing) { if (disposing && this.components != null) this.components.Dispose(); base.Dispose(disposing); } /// /// 设计器支持所需的方法 - 不要修改 /// 使用代码编辑器修改此方法的内容。 /// private void InitializeComponent() { this.SuspendLayout(); this.AutoScaleMode = AutoScaleMode.None; this.BackColor = Color.Transparent; this.Name = nameof(HslPipeLine); this.Size = new Size(335, 21); this.ResumeLayout(false); } } }