views:

1166

answers:

3

Calling TextRenderer.MeasureText as follows:

TextRenderer.MeasureText(myControl.Text, myControl.Font);

and comparing the result to the size of the control to check if text fits. The results are sometimes incorrect. Have observed the following two issues:

  • Often when a Label is set to AutoSize, TextRenderer will report a width that is 1 pixel wider than the auto-sized width of the Control.
  • False negative where TextRenderer reports a width smaller than the control's but the text is still cut off. This occurred with "Estación de trabajo" -- not sure if the accent could somehow affect the width calculation?

Is there any way to improve the accuracy of the MeasureText method? Should I be calling one of the overrides that accepts a device context and/or format flags?

+1  A: 

I don't know if I have a perfect solution but I ran into this when I was doing WinForms a few years back. The way I ended up compensating was by adjusting the returned measurement by a percentage. I cannot recall what I used (maybe 5% or 105?), but I do recall that I ended up using a constant percentage across the app and always rounded up.

Jason Jackson
Interesting idea for taking care of the false negatives. Could be good as a failsafe but I'm most interested in understanding the reason for the size differences.
Aidan Ryan
+2  A: 

Is there any way to improve the accuracy of the MeasureText method? Should I be calling one of the overrides that accepts a device context and/or format flags?

You have answered your question by yourself. Actually MeasureText based on Win32 DrawTextEx, and this function cannot work without valid device context. So when you call MeasureText override without hdc, it internally create desktop compatible hdc to do measurement.

Of course measurement depends on additional TextFormatFlags. Also keep in mind that Label painting (and measurement) depends on UseCompatibleTextRendering.

So general conclusion you should use MeasureText for your own code, for example when you then call DrawText with exactly same parameters, in all other cases size returned by MeasureText cannot be treated as precise.

If you need to get expected Label size, you should use GetPreferredSize method.

arbiter
Thanks. I'm checking if translated text fits controls, rather than drawing my own text. Do you know how to get the TextFormatFlags for an existing control?
Aidan Ryan
@Aidan, looking into framework source code is the only way. But it is better to redesign your layout if it depends on MesureLayout, use control's AutoSize, and TableLayoutPanel or FlowLayoutPanel to arrange your automatically sized controls. Docking is also an option.
arbiter
Note that to do the specific comparison I was trying to do (check if text fits), pass Size.Empty to GetPreferredSize and compare to the actual Control.Size.
Aidan Ryan
A: 

Check out the TextFormatFlags parameter to this function:

TextRenderer::MeasureText(String, Font, Size, TextFormatFlags)

http://msdn.microsoft.com/en-us/library/8wafk2kt.aspx

"The Size, in pixels, of text drawn on a single line with the specified font. You can manipulate how the text is drawn by using one of the DrawText overloads that takes a TextFormatFlags parameter. For example, the default behavior of the TextRenderer is to add padding to the bounding rectangle of the drawn text to accommodate overhanging glyphs. If you need to draw a line of text without these extra spaces you should use the versions of DrawText and MeasureText that take a Size and TextFormatFlags parameter. For an example, see MeasureText(IDeviceContext, String, Font, Size, TextFormatFlags)."

hth

fusi