如何用虚线绘制区域的轮廓

时间:2015-12-01 10:19:47

标签: c# winforms

为了进一步提出上一个问题,即How do I draw the outline of a collection of rectangles?,我想知道是否可以用虚线绘制区域的轮廓,而不是实心?

我有一个名为Deck的类,它包含一个Region对象。构造函数创建一个大矩形,应该代表地板的表面。

public Deck( double x, double y, double width, double height )
{
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;

    region = new Region( new RectangleF( (float)x, (float)y,  (float)width, (float)height ) );
}

然后,我希望用户能够" cut"地板上的洞,或者#34;填充"向上钻孔,但允许任何矩形形状被切掉,也许只有一部分可以放回去。为此,我创建了方法,基本上将Union和Exclude方法包装为从区域添加或删除矩形。

public void RemoveA( double x, double y, double width, double height )
{
    var rect = new RectangleF( (float)x, (float)y, (float)width, (float)height );
    region.Exclude( rect );
}

public void AddA( double x, double y, double width, double height )
{
    var rect = new RectangleF( (float)x, (float)y, (float)width, (float)height );
    region.Union( rect );
}

然后绘制甲板和切口的轮廓(基本上是区域)我使用以下代码来自彼得对上述问题的回答

[DllImport( @"gdi32.dll" )]
static extern bool FrameRgn( IntPtr hDC, IntPtr hRgn, IntPtr hBrush, int nWidth, int nHeight );
public void Draw( Graphics g, Color c, float scale )
{
    COLORREF colorref = new COLORREF( c );
    IntPtr hdc = IntPtr.Zero, hbrush = IntPtr.Zero, hrgn = IntPtr.Zero;

    try
    {
        hrgn = this.region.GetHrgn( g );
        hdc = g.GetHdc();
        hbrush = CreateSolidBrush( colorref.colorref );

        FrameRgn( hdc, hrgn, hbrush, 2, 2 );
    }
    finally
    {
        if (hrgn != IntPtr.Zero)
        {
            region.ReleaseHrgn( hrgn );
        }

        if (hbrush != IntPtr.Zero)
        {
            DeleteObject( hbrush );
        }

        if (hdc != IntPtr.Zero)
        {
            g.ReleaseHdc( hdc );
        }
    }
}

这很好用,但是我想知道我是否能找到一种用虚线或虚线画出轮廓的方法,浏览了gdi32.dll和其他论坛上的文档,但是找不到任何东西允许我使用虚线。

然后我尝试使用GraphicsPath而不是Region,但是这开始产生其他问题,试图确定GraphicsPath何时将Rectangle视为添加或删除,取决于其FillMode。这是我跑的测试应用程序。

[DllImport( @"gdiplus.dll" )]
public static extern int GdipWindingModeOutline( HandleRef path, IntPtr matrix, float flatness );
GraphicsPath gPath = null;
public Form1()
{
    InitializeComponent();

    gPath = new GraphicsPath();
    // draw the main rectangle (Deck) that the user can then cut recangular holes out of or add back in
    gPath.AddRectangle( new RectangleF( 10, 10, 150, 150 ) );

    // cut holes in the main rectangle, default FillMode (Alternate)
    gPath.AddRectangle( new System.Drawing.Rectangle( 30, 30, 60, 90 ) );
    // make this rectangle to overlap the one above, on purpose
    gPath.AddRectangle( new System.Drawing.Rectangle( 80, 30, 60, 90 ) );

    this.Paint += Form1_Paint;
}

private void Form1_Paint( object sender, PaintEventArgs e )
{
    using (Pen outlinePen = new Pen( Color.Red, 2 ))
    {
            outlinePen.DashStyle = DashStyle.Dash;
            e.Graphics.DrawPath( outlinePen, gPath );
    }
}

我得到的结果是较大的矩形的轮廓,但另一个2"孔"矩形重叠,没有好处。

Result 1

如果我在Paint方法中使用GpidWindingModeOutline方法,我可以摆脱重叠

private void Form1_Paint( object sender, PaintEventArgs e )
{
    HandleRef handle =
       new HandleRef( gPath, (IntPtr)gPath.GetType().GetField( "nativePath", BindingFlags.NonPublic | BindingFlags.Instance ).GetValue( gPath ) );
    //Change path so it only contains the outline    
    GdipWindingModeOutline( handle, IntPtr.Zero, 0.25F );

    using (Pen outlinePen = new Pen( Color.FromArgb( 255, Color.Red ), 2 ))
    {
        outlinePen.DashStyle = DashStyle.Dash;
        e.Graphics.DrawPath( outlinePen, gPath );
    }
}

虽然仍然不好,因为我现在看到的只是主要的外部矩形。

当矩形共享边缘或边缘的一部分时,会出现另一种复杂情况。然后GraphicsPath在这个共享边上绘制一条实线,而Region对象根本不会绘制一条,这就是我想要的。

Result 2

我意识到我可以执行重叠矩形的检查,合并共享和边缘等,当矩形只共享边缘的一部分或角落重叠时,它变得复杂。一个地区负责所有那些伟大的事情,但遗憾的是,它似乎不是一种用虚线绘制轮廓的方法。

0 个答案:

没有答案