Can you measure the width of a string more exactly in WIN32 than using the GetTextMetrics function and using tmAveCharWidth*strSize?
-
3You should note that "tmAveCharWidth*strSize" is only sane for fixed width fonts. – Evan Teran Jul 14 '09 at 17:08
-
Even for a decidedly fixed-width font (Iosevka), `tmAveCharWidth` does not match `tmMaxCharWidth` although I am not entirely sure what it would mean in practice nor do I have the code at hand to tell you if, say, the second number is some integer-multiple of the first (suggesting e.g. a grapheme spanning multiple glyph "boxes"). – Armen Michaeli Mar 31 '23 at 12:18
5 Answers
Try using GetTextExtentPoint32. That uses the current font for the given device context to measure the width and height of the rendered string in logical units. For the default mapping mode, MM_TEXT, 1 logical unit is 1 pixel.
However, if you've changed the mapping mode for the current device context, a logical unit may not be the same as a pixel. You can read about the different mapping modes on MSDN. With the mapping mode, you can convert the dimensions returned to you by GetTextExtentPoint32 to pixels.

- 39,212
- 14
- 67
- 75
-
2GetTextExtentPoint32 uses "logical units"; not pixels: http://msdn.microsoft.com/en-us/library/dd144938%28VS.85%29.aspx – user20493 Sep 18 '12 at 19:55
-
2@user good catch. When the mapping mode is MM_TEXT (the default), 1 logical unit = 1 pixel, but that doesn't necessarily have to be true. I'll modify my answer. – Nick Meyer Sep 19 '12 at 18:12
-
And, nowadays, you also have to worry about high DPI scaling if your process is not marked as high-DPI aware. – Adrian McCarthy Mar 30 '17 at 16:20
I don't know for certain, but it seems that:
HDC hDC = GetDC(NULL);
RECT r = { 0, 0, 0, 0 };
char str[] = "Whatever";
DrawText(hDC, str, strlen(str), &r, DT_CALCRECT);
might work.

- 5,393
- 9
- 44
- 53

- 87,561
- 32
- 179
- 238
-
-
5This is a much better solution than `GetTextExtentPoint32` since it takes the mapping mode out of equation. One thing the author needs to change is the flags for `DrawText`. Set it to `DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE`. The resulting width can be then calculated as `abs(r.right - r.left);` – c00000fd Jun 09 '13 at 01:44
VOID Example_MeasureString(HDC hdc) { Graphics graphics(hdc); // Set up the string. WCHAR string[] = L"Measure Text"; Font font(L"Arial", 16); RectF layoutRect(0, 0, 100, 50); RectF boundRect; // Measure the string. graphics.MeasureString(string, 12, &font, layoutRect, &boundRect); // Draw a rectangle that represents the size of the string. graphics.DrawRectangle(&Pen(Color(255, 0, 0, 0)), boundRect); }

- 97,037
- 24
- 136
- 212
-
Your method is definitely better than using GetTextExtentPoint32(). – William Chan Oct 31 '15 at 05:24
-
I have a confused thing. what is the layoutRect? I don't understand it – krosshj Aug 02 '16 at 07:44
-
1Instead of `RectF layoutRect(0, 0, 100, 50);` you can use `PointF pointF(0.0f, 0.0f);` for `x` and `y`. See the example from here https://stackoverflow.com/questions/66795957/c-gettextextentpoint32-doesnt-give-the-correct-size/66797699?noredirect=1#comment118098332_66797699 – Polar Mar 26 '21 at 02:53
Depending on how you are using this, you can use DrawText with DT_CALCRECT specified and it will (its always done it fairly accurately for me) calculate the size of the required rectangle based on the text/font/etc.

- 5,971
- 5
- 29
- 36
For Builder C++ first make new TLabel dynamicly and then change font attributes.Set your TLabel as autosize.Then you can get you TLabel width witch represents your string width in pixels.
int WidthPixels (String font, int size, String text)
{
TLabel* label = new TLabel(Form1); // dynamic TLabel
label->AutoSize = true;
label->Font->Name = font; // your font
label->Font->Size = size; // your font size
label->Caption = text; // your string
return label->Width;
}
int width = WidthPixels("Times New Roman", 19 , "Hey");