web-dev-qa-db-fra.com

TextRenderer.MeasureText et Graphics.MeasureString ne correspondent pas en taille

Ce n'est pas un problème d'arrondi. Différence ~ 5+ pixels.

Chaîne de scénario de test: "" MACD (26,12,9) -0.000016 "

e.Graphics.MeasureString("MACD (26,12,9) -0.000016", SystemFonts.DefaultFont).Width)
TextRenderer.MeasureText("MACD (26,12,9) -0.000016", SystemFonts.DefaultFont).Width)

Le résultat est toujours:

139.3942
134

Pourquoi y a-t-il tant de différence de taille? J'ai juste besoin du tour de largeur de chaîne en dehors de la méthode Paint. Mais il doit correspondre à MeasureString ou vice versa.

27
Aseem Gautam

TextRenderer utilise GDI pour afficher le texte, tandis que Graphics utilise GDI +. Les deux utilisent une méthode légèrement différente pour la présentation du texte, les tailles sont donc différentes.

Lequel vous devez utiliser dépend de ce qui sera éventuellement utilisé pour dessiner le texte. Si vous le dessinez avec GDI + Graphics.DrawString, mesure à l'aide de Graphics.MeasureString. Si vous dessinez en utilisant GDI TextRenderer.DrawText, mesure à l'aide de TextRenderer.MeasureText.

Si le texte s'affiche dans un contrôle Windows Forms, il utilise TextRenderer si UseCompatibleTextRendering est défini sur false (qui est la valeur par défaut).

En lisant entre les lignes de votre question, vous semblez utiliser TextRenderer car vous n'avez pas d'instance Graphics en dehors de l'événement Paint. Si tel est le cas, vous pouvez en créer un vous-même pour effectuer la mesure:

using( Graphics g = someControl.CreateGraphics() )
{
    SizeF size = g.MeasureString("some text", SystemFonts.DefaultFont);
}

Si vous n'avez pas accès à un contrôle pour créer l'instance graphique, vous pouvez l'utiliser pour en créer un pour l'écran, ce qui fonctionne très bien à des fins de mesure.

using( Graphics g = Graphics.FromHwnd(IntPtr.Zero) )
{
     SizeF size = g.MeasureString("some text", SystemFonts.DefaultFont);
}
58
Sven

J'ai créé la classe suivante pour utiliser MeasureString en dehors de l'événement Paint, et cela fonctionne plutôt bien.

public interface ITextMeasurer
    {
        SizeF MeasureString(string text, Font font, StringFormat format);
    }

    public class TextMeasurer : ITextMeasurer
    {
        private readonly Image _fakeImage;
        private readonly Graphics _graphics;

        public TextMeasurer()
        {
            _fakeImage = new Bitmap(1, 1);
            _graphics = Graphics.FromImage(_fakeImage);
        }

        public SizeF MeasureString(string text, Font font, StringFormat format)
        {
            return _graphics.MeasureString(text, font, int.MaxValue, format);
        }
    }
1
Aseem Gautam