调用后,.Net DrawString字体引用发生了变化

时间:2010-09-28 15:29:09

标签: c# .net graphics onpaint drawstring

给出以下代码。第一个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的覆盖范围内,但我认为现在这样做......

4 个答案:

答案 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来呈现?