1

给定以下代码。第一个 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

4 回答 4

2

不,我看不出这怎么可能发生——它不像第一次调用知道变量f——它只知道它在DrawString被调用时的值。参数(Font引用)是按值传递的,而不是按引用传递的。

我可以想象这会导致问题的唯一方法是,如果Graphics对象记住了它的“当前”字体(并在对 的调用中将其重置DrawString)但推迟了实际的绘图。那会产生各种令人讨厌的影响——我看不到它发生。

基本上,就DrawString调用而言,就好像您使用了两个不同的变量。

于 2010-09-28T15:30:38.693 回答
2

是的,当您的程序接近消耗 10,000 个 GDI 句柄时,奇怪的事情开始发生。它几乎肯定会影响 Windows 字体映射器,而不必引发异常。您的程序正在玩带有此潜在问题的俄罗斯轮盘赌,因为您没有对您使用的字体调用 Dispose()。如果垃圾收集器运行的频率不够高,那么您很可能会让那把枪开火。你需要这样写:

using (Font fp = new Font("Arial", this.TextSize)) {
    // etc..
}

还要注意代码中的另一个错误,您正在使用 TextRenderer.MeasureText 但使用 Graphics.DrawString 进行绘图。测量值不相同。您必须使用 Graphics.MeasureString。

于 2010-09-28T16:04:34.940 回答
0

提供的代码看不到任何问题。在您的完整代码中,绘图位置是否可能不正确?

您是否 100% 确定在 Arial 中呈现的字符串值只能通过使用 TNR 字体调用 DrawString 来呈现?

于 2010-09-28T15:39:02.957 回答
0

飞碟盖住了底座。我已经做了很多 GDI+,但我从未见过你描述的行为。很可能是由于此代码未显示的其他一些影响。

于 2010-09-28T15:33:25.833 回答