我试图弄清楚gdi +图形容器如何与不同的图形单元一起工作。看看下面的代码。它编译,您可以将其粘贴到一个全新的形式。
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, 0, 2, 2),
GraphicsUnit.Pixel);
// Draw the outer rectangle
gfx.DrawRectangle(pen, new Rectangle(0, 0, 2, 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, 0.1f, 1, 1),
new RectangleF(0, 0, 1, 1),
GraphicsUnit.Pixel);
// Draw the inner rectangle
gfx.DrawRectangle(pen, new Rectangle(0, 0, 1, 1));
gfx.EndContainer(innerContainer);
gfx.EndContainer(outerContainer);
}
上面的代码是嵌套图形容器的一个非常简单的例子,我没有使用缩放转换。这是在使用上面的绘制处理程序时表单的样子:
非常简单。现在,我将尝试描述问题所在。
这是BeginContainer
方法的签名:
public GraphicsContainer BeginContainer(
RectangleF dstrect,
RectangleF srcrect,
GraphicsUnit unit
)
我未能理解的内容是GraphicsUnit unit
论点。
来自MSDN:
GraphicsUnit枚举的成员,指定容器的度量单位。
这似乎 是真的!
正如您在我的代码中所看到的,我使用英寸单位:gfx.PageUnit = GraphicsUnit.Inch
。
但是,当我创建容器时,这就是我作为BeginContainer
方法的单位参数传递的内容:GraphicsUnit.Pixel
。创建容器后会发生什么? 正在使用英寸(我真正想要的)。但是,如果我将GraphicsUnit.Inch
(或毫米或任何其他)传递给参数,则使用像素。所以,似乎为了实现我想要的(使用英寸),我必须指定像素?
这对我没有意义。您可以尝试在上面的代码中使用BeginContainer
方法更改单位,并观察奇怪的结果。我已经阅读了MSDN以及我可以收集到的所有内容,但我仍然无能为力。
我正在编写使用gdi +绘制大量内容的软件,而且它使用毫米单位进行打印 - 当我开始使用容器时,我很惊讶我显然需要将像素指定为单位。我真的怀疑任何提到像素的打印代码。一定是我对这件事有很大的误解。
所以,考虑到以上所有问题,我的问题是:此方法中unit
参数的目的是什么?
答案 0 :(得分:8)
不幸的是,就我所知,GDI +是Windows中记录最差的API之一。一些在网上浏览的人很少有人真正使用它,也没有深入了解你的问题。
更不幸的是,GDI + API基本上被直接复制到.NET Graphics
对象。甚至文档大部分也只是逐字复制。请注意.NET Graphics.BeginContainer Method (RectangleF, RectangleF, GraphicsUnit)和Windows Graphics.BeginContainer(const RectF, const RectF, Unit) method页面之间的相似之处。
为了使事情进一步复杂化,有this blog entry令人着迷地读到:
另一个例子是Graphics类中的Save和BeginContainer方法,它们的执行方式非常不同,但具有相同的MSDN文档,无法区分这两个调用
...但是没有详细说明这两种方法实际上是如何不同的。
现在,所有这些,通过一些实验,我认为我已经解码了参数和行为:
unit
参数似乎用于指定用于srcrect
参数的单位dstrect
参数以当前用于Graphics
对象的单位指定Graphics.PageUnit
设置回默认值GraphicsUnit.Display
我在文档中找不到上面前两点的任何提示。只有通过实验和仔细观察才能了解到这一点,坦率地说,如果没有实际的文件来支持我的结论,我仍然不能100%肯定它。
是<{1}}方法文档中第三点的提示:
BeginContainer方法建立的图形状态包括默认图形状态的渲染质量;调用方法时存在的任何渲染质量状态更改都将重置为默认值。
乍一看,这句话似乎只是说'#34;渲染质量状态发生变化&#34;被重置。但是仔细阅读,人们会发现状态的一部分只是被特别唤醒,因为它被重置的所有状态中包含 。当然,更仔细的阅读并没有获得任何额外的理解:(,但至少有一个人可以看到这句话不应被视为所有内容的最后一句话那个重置。
因此,让事情正常工作的关键是在每一步中指定你想要工作的单位(例如BeginContainer()
):在创建容器之前的初始设置中,在{ {1}}(但此处,仅用于控制GraphicsUnit.Inch
的解释方式),最后在BeginContainer()
之后,再次设置srcrect
属性。
当我这样做时,我能够使用我想绘制的任何单位。我甚至可以混合搭配,当然,与我绘制的矩形相比,这会导致容器矩形传递一些非直观的值。
例如,这里是一个片段,我使用英寸表示初始BeginContainer()
状态,毫米表示容器:
Graphics.PageUnit
产生这张图片:
所以我能够在容器外面绘制一个2x2英寸的矩形,然后在容器内部绘制一个1.5x1.5英寸的矩形,但是使用毫米(在参数中明确转换,只是为了制作)我自己更清楚自己所做的事情。
答案 1 :(得分:0)
也许,你根本不需要关心。
我也未能将正确的参数传递给Graphics.BeginContainer
。
但是,使用Transform
方法(最后为ResetTransform
)可以很好地解决我必须解决的问题。
因此,在尝试理解容器之前,首先考虑Transform
方法。