给出以下代码。第一个DrawString方法是否有可能用Arial而不是Times New Roman绘制?
protected override void OnPaint(PaintEventArgs pe)
{
Font f = new Font("Times New Roman", this.TextSize);
pe.Graphics.DrawString("Test 1", f, Brushes.Black, loc);
f = new Font("Arial", this.TextSize);
pe.Graphics.DrawString("Test 2", f, Brushes.Black, loc);
}
我有一个问题,基本上这段代码是间歇性地用错误的字体绘制第一个字符串。我已经将代码更改为现在有两个静态字体引用,但由于我无法重现代码,我无法确定它是否解决了问题。
注意:loc是一个可以被实际代码更改的位置,我在这里删除了一些代码来简化
这是我修复它的整个方法。如果你看不出它有什么问题 - 我会责怪一些宇宙射线或其他东西......
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
if (bcf == null)
{
FontFamily[] families = pfc.Families;
foreach (FontFamily ff in families)
{
if (ff.Name.Equals("Free 3 of 9"))
{
bcf = ff;
}
}
}
if (bcf != null)
{
Font f = new Font(bcf, this.BarcodeSize);
SizeF s = TextRenderer.MeasureText(barcodeValue, f);
Rectangle r = pe.ClipRectangle;
Point loc = new Point(0, 0);
if (s.Width < r.Width)
{
loc.X = (int)Math.Ceiling((r.Width - s.Width) / 2);
}
pe.Graphics.DrawString(barcodeValue, f, Brushes.Black, loc);
float barcodeBottom = s.Height + 5;
Font fp = new Font("Arial", this.TextSize);
s = TextRenderer.MeasureText(barcodeValue, fp);
r = pe.ClipRectangle;
loc = new Point(0, (int)Math.Ceiling(barcodeBottom));
if (s.Width < r.Width)
{
loc.X = (int)Math.Ceiling((r.Width - s.Width) / 2);
}
if (s.Height + loc.Y > r.Height)
{
loc.Y = (int)Math.Ceiling(r.Height - (s.Height));
}
pe.Graphics.FillRectangle(Brushes.White, new Rectangle(loc, new Size((int)Math.Ceiling(s.Width), (int)Math.Ceiling(s.Height))));
pe.Graphics.DrawString(barcodeValue, fp, Brushes.Black, loc);
}
}
现在,固定代码如下所示。现在更少的GDI呼叫:
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
if (bcf != null)
{
Rectangle r = pe.ClipRectangle;
Point loc = new Point(0, 0);
if (barcodeDimensions.Width < r.Width)
{
loc.X = (int)Math.Ceiling((r.Width - barcodeDimensions.Width) / 2);
}
pe.Graphics.DrawString(barcodeValue, barcodeFont, Brushes.Black, loc);
float barcodeBottom = barcodeDimensions.Height + 5;
r = pe.ClipRectangle;
loc = new Point(0, (int)Math.Ceiling(barcodeBottom));
if (plaintextDimensions.Width < r.Width)
{
loc.X = (int)Math.Ceiling((r.Width - plaintextDimensions.Width) / 2);
}
if (plaintextDimensions.Height + loc.Y > r.Height)
{
loc.Y = (int)Math.Ceiling(r.Height - (plaintextDimensions.Height));
}
pe.Graphics.FillRectangle(Brushes.White, new Rectangle(loc, new Size((int)Math.Ceiling(plaintextDimensions.Width), (int)Math.Ceiling(plaintextDimensions.Height))));
pe.Graphics.DrawString(barcodeValue, plaintextFont, Brushes.Black, loc);
}
}
如果我打算让这个更加优化,我会将矩形测量部分放在OnResize的覆盖范围内,但我认为现在这样做......
答案 0 :(得分:2)
不,我看不出这可能会发生什么 - 它不像第一次调用知道变量f
- 它只知道调用DrawString
时它的值。参数(Font
引用)按值传递,而不是通过引用传递。
我可以想象这导致问题的唯一方法是Graphics
对象是否记住其“当前”字体(并在调用DrawString
时重置它)但是推迟实际绘图。这会有各种令人讨厌的影响 - 我看不到它发生。
基本上,就DrawString
调用而言,就像使用两个不同的变量一样。
答案 1 :(得分:2)
是的,当您的程序接近消耗10,000个GDI句柄时,会发生奇怪的事情。它几乎肯定会影响Windows字体映射器,而不必抛出异常。你的程序正在玩这个潜在问题的俄罗斯轮盘赌,因为你没有在你使用的字体上调用Dispose()。如果垃圾收集器运行频率不够,那么你可能会把那把枪拿掉。你需要这样写:
using (Font fp = new Font("Arial", this.TextSize)) {
// etc..
}
另请注意代码中的另一个错误,即使用TextRenderer.MeasureText但使用Graphics.DrawString绘图。测量结果不尽相同。您必须使用Graphics.MeasureString。
答案 2 :(得分:0)
Skeet覆盖了基础案例。我做了很多GDI +,我从未见过你描述过的行为。很可能是由于此代码未显示的其他一些影响。
答案 3 :(得分:0)
看不到提供的代码有任何问题。在您的完整代码中,绘图位置是否可能不正确?
您是否100%确定在Arial中呈现的字符串值只能通过使用TNR字体调用DrawString来呈现?