sjsam
sjsam

Reputation: 21965

How to make the 'DrawText' rectangle just fit the text?

The documentation [ here ] says if we use the DT_CALCRECT flag, then below would be done :

Determines the width and height of the rectangle. If there are multiple lines of text, DrawText uses the width of the rectangle pointed to by the pRect parameter and extends the base of the rectangle to bound the last line of text. If there is only one line of text, DrawText modifies the right side of the rectangle so that it bounds the last character in the line. In either case, DrawText returns the height of the formatted text but does not draw the text.

It is clear from the description that DT_CALCRECT will make the DrawText not to draw the content so that I should do something like

DrawTextExA(hdc, fromsqlite->descrip, -1, &rect, DT_CALCRECT, NULL);
// On debugging, I can see that rect is being modified in the above step.
if (DrawTextExA(hdc, fromsqlite->descrip, -1, &rect,
            DT_LEFT | DT_EDITCONTROL | DT_WORDBREAK, NULL) == 0) {
MessageBox(NULL, L"DrawText failed", NULL, MB_OK);
}

Now the problem is that the width of the rectangle should be fixed. So, I just want the base of the rectangle rect to be extended. In my case though fromsqlite->descrip which is retrieved from a sqlite database is always considered as single-line text.

Any help is appreciated.

Upvotes: 4

Views: 2481

Answers (1)

Barmak Shemirani
Barmak Shemirani

Reputation: 31599

DT_WORDBREAK should be added to break the single line of text.

DT_CALCRECT should be combined with the final format to get the rectangle.

Documentation: DrawText function (GDI function)

DT_WORDBREAK
Breaks words. Lines are automatically broken between words if a word would extend past the edge of the rectangle specified by the lpRect parameter. A carriage return-line feed sequence also breaks the line.

If this is not specified, output is on one line.

Example:

RECT rc={ 0, 0, 200, 0 };
const wchar_t* text = L"word1 word2 word3 word4 word5";
UINT format = DT_LEFT | DT_TOP | DT_EDITCONTROL | DT_WORDBREAK;
DrawText(hdc, text, -1, &rc, format | DT_CALCRECT);
DrawText(hdc, text, -1, &rc, format);

Output would be similar to the following (depending on font size)

word1 word2 word3
word4 word5

Is DT_EDITCONTROL necessary?

Consider this example:

text = L"SingleLinexxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
format = DT_LEFT | DT_TOP | DT_WORDBREAK;
DrawText(hdc, text, -1, &rc, format | DT_CALCRECT);
DrawText(hdc, text, -1, &rc, format);

This time "word" could be longer that rectangle's width, line will not break, text will spill over on the right side.

You may wish to combine the format with DT_EDITCONTROL or other flags like DT_WORD_ELLIPSIS to make sure there is no spill over on the right side.

DrawTextEx uses the same DT_XXXX flags.

Side note: if your text is UTF-8, you can convert to UTF-16 using MultiByteToWideChar, rather than using DrawTextA which expects ANSI input.

Upvotes: 5

Related Questions