void Form2_Paint(object sender,PaintEventArgs e) { var gfx = e.Graphics; System.Diagnostics.Debug.WriteLine("DpiX={0},DpiY={1}",gfx.DpiX,gfx.DpiY); gfx.PageUnit = GraphicsUnit.Inch; var pen = new Pen(Color.Black,0.01f); // Create outer container,2 inches in size with X and Y set to 0.1 inches var outerContainer = gfx.BeginContainer( new RectangleF(0.1f,0.1f,2,2),new RectangleF(0,GraphicsUnit.Pixel); // Draw the outer rectangle gfx.DrawRectangle(pen,new Rectangle(0,2)); // Create inner container,1 inch in size with X and Y set to 0.1 inches var innerContainer = gfx.BeginContainer( new RectangleF(0.1f,1,1),GraphicsUnit.Pixel); // Draw the inner rectangle gfx.DrawRectangle(pen,1)); gfx.EndContainer(innerContainer); gfx.EndContainer(outerContainer); }
上面的代码是嵌套图形容器的一个非常简单的例子,我没有使用缩放变换.这是在使用上面的paint handler时的形式如何:
这很简单现在,我将尝试描述问题.
这是BeginContainer方法的一个签名:
public GraphicsContainer BeginContainer( RectangleF dstrect,RectangleF srcrect,GraphicsUnit unit )
我不明白的是GraphicsUnit单位参数.
从MSDN:
Member of the GraphicsUnit enumeration that specifies the unit of measure for the container.
这似乎不是真的!
正如你可以在我的代码中看到的,我使用英寸单位:gfx.PageUnit = GraphicsUnit.Inch.
但是,当我创建容器这是我作为单位参数传递给BeginContainer方法:GraphicsUnit.Pixel.容器创建后会发生什么?正在使用英寸(我真正想要的).但是如果我将GraphicsUnit.Inch(或毫米或其他任何东西)传递给参数,则使用像素.所以,为了完成我想要的(使用英寸),我必须指定像素?
这对我来说没有意义.您可以尝试在上述代码中的BeginContainer方法中更改单位,并观察奇怪的结果.我已经阅读了MSDN和我可以收集的一切,但我仍然无法理解.
我正在编写使用gdi绘制很多东西的软件,它使用毫米单位进行打印 – 当我开始使用容器时,我非常惊讶,我显然需要指定像素为单位.我真的怀疑提到像素的任何打印代码.一定是我对这件事情有很大的误解.
所以,以上所有的考虑,我的问题是:这个方法中单位参数的目的是什么?
解决方法
更不幸的是,GDI API基本上被复制到.NET Graphics对象.即使文件大部分是逐字复制的.请注意.NET Graphics.BeginContainer Method (RectangleF,RectangleF,GraphicsUnit)和Windows Graphics.BeginContainer(const RectF,const RectF,Unit) method页面之间的相似之处.
为了进一步使事情复杂化,有this blog entry引人注目的是:
Another example is the Save and BeginContainer methods in Graphics class,which perform very differently,yet have the same MSDN documentation that fails to differentiate between the two calls
…但没有详细说明这两种方法实际上是不同的.
现在,所有这一切,通过一些实验,我想我解码了参数和行为:
>单位参数似乎用于指定用于srcrect参数的单位
> dstrect参数在Graphics对象当前使用的单位中指定
>新的容器将其Graphics.PageUnit设置回到GraphicsUnit.Display的默认值
文件中没有提到上述前两点的提示.只有通过实验和仔细观察,我才明白,坦白说,没有实际的文件来支持我的结论,我还没有百分百的肯定.
The graphics state established by the BeginContainer method includes the rendering qualities of the default graphics state; any rendering-quality state changes existing when the method is called are reset to the default values.
乍一看,这句话似乎只是说,只有“渲染质量状态改变”被重置.但是仔细阅读,可以看出,国家的一部分,只是简单地被特别引用,因为它被包含在被重置的所有状态中.认为,更仔细的阅读不会获得任何额外的理解:(,但至少有一个可以看到句子不应该被视为重置所有内容的最后一个字.
所以让事情正常工作的关键是在每一步都要指定要工作的单元(例如GraphicsUnit.Inch):在创建容器之前的初始设置中,在调用BeginContainer() (但在这里,只是为了控制srcrect的解释方式),然后最后刚刚在BeginContainer()之后,再次设置Graphics.PageUnit属性.
当我这样做的时候,我能够使用我想画的任何单位.我甚至可以混合搭配,虽然这与我正在绘制的矩形相比,导致了一些非直观的值被传递给容器矩形.
例如,这里是一个代码片段,其中我使用英寸的初始图形状态,毫米的容器:
gfx.PageUnit = GraphicsUnit.Inch; using (Pen blackPen = new Pen(Color.Black,0.01f)) using (Pen redPen = new Pen(Color.Red,0.01f)) { gfx.DrawRectangle(blackPen,.25f,2); var outerContainer = gfx.BeginContainer( new RectangleF(.25f,2 * 25.4f,2 * 25.4f),GraphicsUnit.Millimeter); gfx.PageUnit = GraphicsUnit.Millimeter; gfx.DrawRectangle(redPen,.25f * 25.4f,1.5f * 25.4f,1.5f * 25.4f); gfx.EndContainer(outerContainer); }
这产生了这个图像:
所以我可以在容器外面画一个2×2英寸的矩形,然后在容器内部画一个1.5×1.5英寸的矩形,但是用毫米(这个参数中明确的转换),只是为了让自己更清楚我正在做).