为了进一步提出上一个问题,即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"孔"矩形重叠,没有好处。
如果我在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对象根本不会绘制一条,这就是我想要的。
我意识到我可以执行重叠矩形的检查,合并共享和边缘等,当矩形只共享边缘的一部分或角落重叠时,它变得复杂。一个地区负责所有那些伟大的事情,但遗憾的是,它似乎不是一种用虚线绘制轮廓的方法。