0

我有一个程序有很多代表管道(油管)的直线。这些线条是用户控件,在每个控件的 Paint 事件中绘制线条,垂直线条的示例代码如下:

e.Graphics.DrawLine(linePen, new Point(0, 0), new Point(0, this.Height));

问题是我想显示管道中油的流动方向,因此需要以某种方式添加箭头。StartCap 和 EndCap 在这里不起作用,原因如下:

用户控件本身必须与线条(管道)的宽度完全一致,才能在线条周围没有任何“死区”,这将在稍后与我的表单上的其他用户控件重叠。如果使用 StartCap 或 EndCap,以及例如 2 像素的线宽,用户控件必须更宽才能绘制箭头(StartCap 或 EndCap)。

简单的方法是使“空白”区域透明,但在谷歌搜索很长时间后我放弃了;似乎没有一种可靠的方法可以通过用户控件来实现这一点。

然后我想我可以制作一个只绘制箭头的单独用户控件,但是我仍然遇到覆盖其他用户控件的未绘制区域的问题。

有没有人建议如何:

  • 使未绘制的用户控制区域透明?
  • 实现上述目标的其他方法?

由于我的“管道”只有 2 像素宽,因此不可能在线/管道内绘制任何内容:(

非常感谢任何建议/意见!

4

1 回答 1

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处理的帮助下。但是,对于您的要求,在许多情况下使用几乎是最佳选择。CustomStartCapCustomEndCapRegion

更新

如果您希望使用Background我们使用的透明解决方案PenCustomLineCap不是裁剪Region,则VerticalArrow必须继承自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更改ForeColor.

于 2013-08-01T15:57:26.873 回答