简体   繁体   English

绘制具有透明背景的形状

[英]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: 有没有人建议如何:

  • make the user control area that is not drawn on transparent? 使未绘制的用户控制区域透明?
  • some other approach to achieve the above? 实现上述目标的其他方法?

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的帮助下,并处理属性CustomStartCapCustomEndCap However as for your requirement, using Region is almost the best choice in many cases. 但是,根据您的要求,在许多情况下,使用Region几乎是最佳选择。

UPDATE 更新

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 (我们使用PenCustomLineCap而不是裁剪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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM