我有一个程序,有很多直线代表管道(油管)。 这些行是用户控件,其中在每个控件的Paint事件中绘制线条,并使用以下示例代码表示垂直线:
e.Graphics.DrawLine(linePen, new Point(0, 0), new Point(0, this.Height));
问题在于我想显示管道中油的流向,因此需要以某种方式添加箭头。 由于以下原因,StartCap和EndCap在此处不起作用:
用户控件本身必须正好是行(管道)的宽度,才能在行周围没有任何“死”区域,这将与我以后的表单上的其他用户控件重叠。 如果使用StartCap或EndCap,并且线宽例如是2像素,用户控件必须更宽,才能绘制箭头(StartCap或EndCap)。
简单的方法是让“空”区域透明,但在谷歌搜索很长一段时间后我放弃了;似乎没有一种可靠的方法来实现用户控制。
然后我想我可以创建一个单独的用户控件,只能绘制箭头,但是我仍然遇到覆盖其他用户控件的未绘制区域的问题。
有没有人建议如何:
由于我的“管道”只有2像素宽,因此无法在线/管道内绘制任何内容:(
非常感谢任何建议/意见!
答案 0 :(得分:3)
有一种方法可以使winforms
中的控件背景透明(彼此重叠)。但是,在运行时移动控件可能会使其闪烁。另一种选择是使用Region
来指定控件的区域,以便理论上它具有任何形状。这就是我能为你做的,只是一个演示:
public partial class VerticalArrow : UserControl
{
public VerticalArrow()
{
InitializeComponent();
Direction = ArrowDirection.Up;
}
public enum ArrowDirection
{
Up,
Down
}
ArrowDirection dir;
public ArrowDirection Direction
{
get { return dir; }
set
{
if (dir != value)
{
dir = value;
UpdateRegion();
}
}
}
//default values of ArrowWidth and ArrowHeight
int arrowWidth = 14;
int arrowHeight = 18;
public int ArrowWidth
{
get { return arrowWidth; }
set
{
if (arrowWidth != value)
{
arrowWidth = value;
UpdateRegion();
}
}
}
public int ArrowHeight
{
get { return arrowHeight; }
set
{
if (arrowHeight != value)
{
arrowHeight = value;
UpdateRegion();
}
}
}
//This will keep the size of the UserControl fixed at design time.
protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
{
base.SetBoundsCore(x, y, Math.Max(ArrowWidth, 4), height, specified);
}
private void UpdateRegion()
{
GraphicsPath gp = new GraphicsPath();
int dx = ArrowWidth / 2 - 1;
int dy = ArrowHeight / 2;
Point p1 = new Point(dx, Direction == ArrowDirection.Up ? dy : 1);
Point p2 = new Point(ArrowWidth - dx, Direction == ArrowDirection.Up ? dy + 1: 1);
Point p3 = new Point(ArrowWidth - dx, Direction == ArrowDirection.Up ? ClientSize.Height : ClientSize.Height - dy);
Point p4 = new Point(dx, Direction == ArrowDirection.Up ? ClientSize.Height : ClientSize.Height - dy);
Point q1 = Direction == ArrowDirection.Up ? new Point(0, ArrowHeight) : new Point(0, ClientSize.Height - ArrowHeight);
Point q2 = Direction == ArrowDirection.Up ? new Point(dx, 0) : new Point(dx, ClientSize.Height);
Point q3 = Direction == ArrowDirection.Up ? new Point(ArrowWidth, ArrowHeight) : new Point(ArrowWidth, ClientSize.Height - ArrowHeight);
if (Direction == ArrowDirection.Up) gp.AddPolygon(new Point[] { p1, q1, q2, q3, p2, p3, p4 });
else gp.AddPolygon(new Point[] {p1,p2,p3,q3,q2,q1,p4});
Region = new Region(gp);
}
protected override void OnSizeChanged(EventArgs e)
{
UpdateRegion();
base.OnSizeChanged(e);
}
}
结果如下:
您可以使用BackColor
更改箭头的颜色。如果我们只需要绘制箭头,代码就会更简单,特别是在System.Drawing.Drawing2D.AdjustableArrowCap
的帮助下处理属性CustomStartCap
和CustomEndCap
。但是,根据您的要求,在许多情况下使用Region
几乎是最佳选择。
如果您希望使用透明Background
的解决方案,我们使用Pen
和CustomLineCap
而不是剪切Region
,VerticalArrow
必须继承{ {1}}。这是代码:
Control
截图:
要更改public class VerticalArrow : Control
{
public VerticalArrow()
{
Width = 30;
Height = 100;
Direction = ArrowDirection.Up;
ArrowHeight = 4;
ArrowWidth = 4;
TrunkWidth = 2;
SetStyle(ControlStyles.Opaque, true);
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20;
return cp;
}
}
public ArrowDirection Direction { get; set; }
public int ArrowHeight { get; set; }
public int ArrowWidth { get; set; }
public int TrunkWidth { get; set; }
Point p1, p2;
public enum ArrowDirection
{
Up,
Down,
UpDown
}
protected override void OnSizeChanged(EventArgs e)
{
p1 = new Point(Width / 2, 0);
p2 = new Point(Width / 2, Height);
base.OnSizeChanged(e);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Pen p = new Pen(ForeColor))
{
using (AdjustableArrowCap cap = new AdjustableArrowCap(ArrowWidth, ArrowHeight))
{
if (Direction == ArrowDirection.Up || Direction == ArrowDirection.UpDown) p.CustomStartCap = cap;
if (Direction == ArrowDirection.Down || Direction == ArrowDirection.UpDown) p.CustomEndCap = cap;
}
p.Width = TrunkWidth;
e.Graphics.DrawLine(p, p1, p2);
}
}
}
,请更改Arrow color
。