using PCHMI; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace CowainHmi { public enum LineDirection { 左上右下, 左下右上, 水平, 垂直 } public enum ArrowType { 无箭头, 结束箭头, 开始箭头, 双箭头 } public partial class ucArrowLine : Control { // 私有字段 private int _lineWidth = 2; private int _arrowWidth = 10; private int _arrowHeight = 5; private LineDirection _angle = LineDirection.水平; private ArrowType _arrowType = ArrowType.无箭头; private Color _lineColor = Color.Teal; private PointF _startPoint = new PointF(50, 50); private PointF _endPoint = new PointF(200, 50); // 公共属性 [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int LineWidth { get { return _lineWidth; } set { _lineWidth = value; Draw(); // 触发重绘 } } // 公共属性 [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public Color LineColor { get { return _lineColor; } set { _lineColor = value; Draw(); // 触发重绘 } } [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int ArrowWidth { get { return _arrowWidth; } set { _arrowWidth = value; Draw(); // 触发重绘 } } [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int ArrowHeight { get { return _arrowHeight; } set { _arrowHeight = value; Draw(); // 触发重绘 } } [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public LineDirection Angle { get { return _angle; } set { _angle = value; CalculatePoint(); // 重新计算终点位置 Draw(); // 触发重绘 } } [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public ArrowType ArrowType { get { return _arrowType; } set { _arrowType = value; CalculatePoint(); // 重新计算终点位置 Draw(); // 触发重绘 } } // 构造函数 public ucArrowLine() { InitializeComponent(); SetStyle(ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor, value: true); SetStyle(ControlStyles.Selectable, value: false); BackColor = Color.Transparent; this.Resize += new EventHandler(this.ArrowLineControl_Resize); this.Size = new Size(300, 100); // 设置控件大小 } // 控件大小改变时调整 private void ArrowLineControl_Resize(object sender, EventArgs e) { CalculatePoint(); Draw(); } // 根据方向更新起点和终点 private void CalculatePoint() { switch (Angle) { case LineDirection.水平: _startPoint = new PointF(0, this.Height / 2); _endPoint = new PointF(this.Width - 4, this.Height / 2); break; case LineDirection.垂直: _startPoint = new PointF(this.Width / 2, 0); _endPoint = new PointF(this.Width / 2, this.Height); break; case LineDirection.左上右下: _startPoint = new PointF(0, 0); _endPoint = new PointF(this.Width, this.Height); break; case LineDirection.左下右上: _startPoint = new PointF(0, this.Height); _endPoint = new PointF(this.Width, 0); break; } } private Bitmap bmp; // 重写OnPaint方法 private void Draw() { bmp = new Bitmap(base.Width, base.Height); Graphics graphics = Graphics.FromImage(bmp); graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; // 绘制线段 Pen linePen = new Pen(LineColor, _lineWidth); graphics.DrawLine(linePen, _startPoint, _endPoint); switch (_arrowType) { case ArrowType.结束箭头: graphics.FillPolygon(linePen.Brush, DrawArrow(graphics, _startPoint, _endPoint, ArrowWidth, ArrowHeight)); break; case ArrowType.开始箭头: graphics.FillPolygon(linePen.Brush, DrawArrow(graphics, _endPoint, _startPoint, ArrowWidth, ArrowHeight)); break; case ArrowType.双箭头: graphics.FillPolygon(linePen.Brush, DrawArrow(graphics, _startPoint, _endPoint, ArrowWidth, ArrowHeight)); graphics.FillPolygon(linePen.Brush, DrawArrow(graphics, _endPoint, _startPoint, ArrowWidth, ArrowHeight)); break; default: break; } BackgroundImage = bmp; //设置显示区域,区域外透明 RegionControl(_startPoint, _endPoint); linePen.Dispose(); graphics.Dispose(); } /// /// 获取箭头的三个点 /// /// private PointF[] DrawArrow(Graphics g, PointF start, PointF end, int arrowWidth, int arrowHeigth) { double angle = Math.Atan2(end.Y - start.Y, end.X - start.X); double left_x = end.X - arrowWidth * Math.Cos(angle); double left_y = end.Y - arrowWidth * Math.Sin(angle); PointF p1 = end; PointF p2 = new PointF { X = (float)(left_x + (arrowHeigth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_y + (arrowHeigth / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p3 = new PointF { X = (float)(left_x - (arrowHeigth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_y - (arrowHeigth / 2) * Math.Sin(angle + Math.PI / 2)) }; return new PointF[] { p1, p2, p3 }; } private void RegionControl(PointF start, PointF end) { PointF[] points = new PointF[] { }; //设置区域,区域外透明 switch (_arrowType) { case ArrowType.无箭头: points = GetNoArrowRegion(_startPoint, _endPoint); break; case ArrowType.结束箭头: points = GetEndArrowRegion(_startPoint, _endPoint); break; case ArrowType.开始箭头: points = GetEndArrowRegion(_endPoint, _startPoint); break; case ArrowType.双箭头: points = GetBothArrowRegion(_startPoint, _endPoint); break; default: break; } GraphicsPath graphicsPath = new GraphicsPath(); graphicsPath.AddPolygon(points); Region region = new Region(graphicsPath); this.Region = region; } private PointF[] GetNoArrowRegion(PointF start, PointF end) { double angle = Math.Atan2(end.Y - start.Y, end.X - start.X); PointF p1 = new PointF { X = (float)(start.X - (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(start.Y - (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p2 = new PointF { X = (float)(start.X + (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(start.Y + (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p3 = new PointF { X = (float)(end.X + (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(end.Y + (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p4 = new PointF { X = (float)(end.X - (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(end.Y - (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; return new PointF[] { p1, p2, p3, p4 }; } private PointF[] GetEndArrowRegion(PointF start, PointF end) { double length = Math.Sqrt((end.Y - start.Y) * (end.Y - start.Y) + (end.X - start.X) * (end.X - start.X)); double angle = Math.Atan2(end.Y - start.Y, end.X - start.X); double left_x = end.X - ArrowWidth * Math.Cos(angle); double left_y = end.Y - ArrowWidth * Math.Sin(angle); PointF p1 = new PointF { X = (float)(start.X - (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(start.Y - (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p2 = new PointF { X = (float)(start.X + (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(start.Y + (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p3 = new PointF { X = (float)(left_x + (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_y + (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p4 = new PointF { X = (float)(left_x + (ArrowHeight / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_y + (ArrowHeight / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p5 = end; PointF p6 = new PointF { X = (float)(left_x - (ArrowHeight / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_y - (ArrowHeight / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p7 = new PointF { X = (float)(left_x - (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_y - (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; return new PointF[] { p1, p2, p3, p4, p5, p6, p7 }; } private PointF[] GetBothArrowRegion(PointF start, PointF end) { double length = Math.Sqrt((end.Y - start.Y) * (end.Y - start.Y) + (end.X - start.X) * (end.X - start.X)); double angle = Math.Atan2(end.Y - start.Y, end.X - start.X); double left_end_x = end.X - ArrowWidth * Math.Cos(angle); double left_end_y = end.Y - ArrowWidth * Math.Sin(angle); double left_start_x = start.X + ArrowWidth * Math.Cos(angle); double left_start_y = start.Y + ArrowWidth * Math.Sin(angle); PointF p1 = new PointF { X = (float)(left_start_x - (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_start_y - (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p2 = new PointF { X = (float)(left_start_x - (ArrowHeight / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_start_y - (ArrowHeight / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p3 = start; PointF p4 = new PointF { X = (float)(left_start_x + (ArrowHeight / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_start_y + (ArrowHeight / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p5 = new PointF { X = (float)(left_start_x + (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_start_y + (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p6 = new PointF { X = (float)(left_end_x + (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_end_y + (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p7 = new PointF { X = (float)(left_end_x + (ArrowHeight / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_end_y + (ArrowHeight / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p8 = end; PointF p9 = new PointF { X = (float)(left_end_x - (ArrowHeight / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_end_y - (ArrowHeight / 2) * Math.Sin(angle + Math.PI / 2)) }; PointF p10 = new PointF { X = (float)(left_end_x - (_lineWidth / 2) * Math.Cos(angle + Math.PI / 2)), Y = (float)(left_end_y - (_lineWidth / 2) * Math.Sin(angle + Math.PI / 2)) }; return new PointF[] { p1, p2, p3, p4, p5, p6, p7, p8, p9, p10 }; } private void RegionControl() { //设置区域,区域外透明 Point[] points = new Point[4] { new Point(0, this.Height / 2 + _lineWidth/2), new Point(0, this.Height / 2 - _lineWidth/2), new Point(this.Width, this.Height / 2 - _lineWidth/2), new Point(this.Width, this.Height / 2 + _lineWidth/2) }; switch (Angle) { case LineDirection.水平: points = new Point[4] { new Point(0, this.Height / 2 + _lineWidth/2), new Point(0, this.Height / 2 - _lineWidth/2), new Point(this.Width, this.Height / 2 - _lineWidth/2), new Point(this.Width, this.Height / 2 + _lineWidth/2) }; break; case LineDirection.垂直: points = new Point[4] { new Point(this.Width/2 - _lineWidth/2, 0), new Point(this.Width/2 + _lineWidth/2, 0), new Point(this.Width/2 + _lineWidth/2, this.Height), new Point(this.Width/2 - _lineWidth/2, this.Height) }; break; case LineDirection.左上右下: points = new Point[4] { new Point(0, base.Height / 2 + _lineWidth/2), new Point(0, base.Height / 2 - _lineWidth/2), new Point(base.Width, base.Height / 2 - _lineWidth/2), new Point(base.Width, base.Height / 2 + _lineWidth/2) }; break; case LineDirection.左下右上: points = new Point[4] { new Point(0, base.Height / 2 + _lineWidth/2), new Point(0, base.Height / 2 - _lineWidth/2), new Point(base.Width, base.Height / 2 - _lineWidth/2), new Point(base.Width, base.Height / 2 + _lineWidth/2) }; break; } GraphicsPath graphicsPath = new GraphicsPath(); graphicsPath.AddPolygon(points); Region region = new Region(graphicsPath); this.Region = region; } } }