418 lines
17 KiB
C#
418 lines
17 KiB
C#
|
|
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();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取箭头的三个点
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|