[英]Draw shape with transparent background
I have a program with a lot of straight lines which represent pipes (oil pipes). 我有一个程序,其中有很多直线,它们代表管道(油管)。 The lines are user controls where the line is drawn in the Paint event of each control with the following sample code for a vertical line:
这些线是用户控件,在每个控件的Paint事件中使用以下垂直线示例代码绘制线:
e.Graphics.DrawLine(linePen, new Point(0, 0), new Point(0, this.Height));
The issue is that I want to display the flow direction of the oil in the pipes, and therefore need to add an arrow somehow. 问题是我想显示管道中机油的流动方向,因此需要以某种方式添加箭头。 StartCap and EndCap don't work here for the following reason:
由于以下原因,StartCap和EndCap在这里不起作用:
The user control itself must be exactly the width of the line (pipe) to not have any "dead" area around the line, which will overlap other user controls on my form later on. 用户控件本身必须恰好是线条(管道)的宽度,以使线条周围没有任何“死”区域,该区域稍后将与我窗体上的其他用户控件重叠。 If using StartCap or EndCap, and a line width of eg 2 pixel, the user control must be wider for the arrow (StartCap or EndCap) to be drawn.
如果使用StartCap或EndCap,并且线宽为2像素,则用户控件必须更宽才能绘制箭头(StartCap或EndCap)。
The easy way would be to make the "empty" area transparent, but after googling for a very long time I gave up; 最简单的方法是使“空”区域透明,但是在使用了很长时间的谷歌搜索之后,我放弃了。 there doesn't seem to be a reliable way to achieve this with a user control.
似乎没有一种可靠的方法可以通过用户控件来实现。
Then I thought I could just make a separate user control that would only draw the arrow, but I then still have the problem with the undrawn area covering the other user controls. 然后我以为我可以制作一个只绘制箭头的单独的用户控件,但是我仍然遇到覆盖其他用户控件的未绘制区域的问题。
Does anyone have a suggestion how to either: 有没有人建议如何:
As my "pipes" are only 2 pixel wide there is no possibility to draw anything inside the line/pipe :( 由于我的“管道”只有2像素宽,因此无法在管道/管道内绘制任何东西:(
Any suggestions/comments are much appreciated! 任何建议/意见,不胜感激!
There is a way to make a Control's Background transparent in winforms
(with overlapping each other). 有一种方法可以使
winforms
控件的背景透明(彼此重叠)。 However moving the control at runtime may make it flicker. 但是,在运行时移动控件可能会使它闪烁。 Another choice is using
Region
to specify the region for your control so that it has theoretically any shape. 另一个选择是使用
Region
来指定控件的区域,以便理论上可以具有任何形状。 This is what I can do for you, just a demo: 这就是我可以为您做的,只是一个演示:
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);
}
}
And here is the result: 结果如下:
You can use BackColor
to change the color of the arrow. 您可以使用
BackColor
更改箭头的颜色。 If we just need to draw the arrow, the code would be simpler, especially with the help of System.Drawing.Drawing2D.AdjustableArrowCap
and deal with properties CustomStartCap
and CustomEndCap
. 如果只需要绘制箭头,则代码会更简单,尤其是在
System.Drawing.Drawing2D.AdjustableArrowCap
的帮助下,并处理属性CustomStartCap
和CustomEndCap
。 However as for your requirement, using Region
is almost the best choice in many cases. 但是,根据您的要求,在许多情况下,使用
Region
几乎是最佳选择。
If you want the solution using transparent Background
in which we use Pen
and CustomLineCap
instead of clipping Region
, the VerticalArrow
has to inherit from Control
. 如果要使用透明
Background
(我们使用Pen
和CustomLineCap
而不是裁剪Region
的解决方案,则VerticalArrow
必须继承自Control
。 Here is the code: 这是代码:
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);
}
}
}
Screenshot: 屏幕截图:
To change Arrow color
change the ForeColor
. 要更改
Arrow color
更改ForeColor
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.