Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
396 views
in Technique[技术] by (71.8m points)

c# - how to measure width of a string precisely?

First of all, question How to measure width of character precisely? which is answered, doesn't really help for this case, so this isn't a duplicate of that.

I have a string. I draw using graphics.DrawString, however when I need to put another one after it, I need to know the precise width of previous string.

For this I use graphics.MeasureString with:

StringFormat format = new StringFormat(StringFormat.GenericTypographic);
format.Alignment = StringAlignment.Center;
format.Trimming = StringTrimming.None;
format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;

I have tried many other functions, just as TextRendered.MeasureText however all of them fail, with all possible combinations of parameters.

the mentioned combination of MeasureString is most close to what I need (it works in most cases, except for special characters), however using characters like # break it. The width is either shorter or longer.

Is there a way to get a precise size of text produced by DrawString function? How does the DrawString calculate the size of drawing area? It must be clearly some other function because the size always differ.

The source code of whole application is here https://gitorious.org/pidgeon/pidgeon-main/ (File where I work with this, is https://gitorious.org/pidgeon/pidgeon-main/blobs/master/scrollback/SBABox.cs)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You just need to eliminate extra width. You can do this by using string format:

GdipStringFormatGetGenericTypographic()

You could also use:

float doubleWidth = g.MeasureString(text+text,...).Width;
float singleWidth = g.MeasureString(text).Width;
float textWidth = doubleWidth-singleWidth;

This will allow you to work with other languages such as Japanese.

On codeproject, Pierre Anaud's solution was to use MeasureCharacterRanges, which returns a region matching exactly the bounding box of the specified string:

static public int MeasureDisplayStringWidth(Graphics graphics, string text, Font font)
{
    System.Drawing.StringFormat format  = new System.Drawing.StringFormat ();
    System.Drawing.RectangleF   rect    = new System.Drawing.RectangleF(0, 0, 1000, 1000);
    var ranges  = new System.Drawing.CharacterRange(0, text.Length);
    System.Drawing.Region[] regions = new System.Drawing.Region[1];

    format.SetMeasurableCharacterRanges (ranges);

    regions = graphics.MeasureCharacterRanges (text, font, rect, format);
    rect    = regions[0].GetBounds (graphics);

    return (int)(rect.Right + 1.0f);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...