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;
}
}
}