Win32 Text Drawing Puzzle

I have a little puzzle for drawing text under Win32. I am trying to draw some instructions for users of my application at the top of the window.

Please refer to the next window (I changed the background color of the text so that you can see the borders)

Demonstration
(source: billy-oneal.com )

I am currently using DrawTextEx to draw text in my window, but the problem is that it does not fill the entire RECTangle that I give it. Do not draw this area just fine until the window size changes:

Demonstration after resize
(source: billy-oneal.com )

When text is repackaged due to window resizing because DrawTextEx does not clear its background, these artifacts remain.

I tried using FillRect to fill the area behind the call to draw text, which eliminates visual artifacts, but then makes the text flicker constantly, as it is completely erased and then completely redrawn on the display.

Any ideas on how you can get a text-free area to draw with the background color?

EDIT: I would like to avoid double buffering the form if possible in the application.

EDIT 2: I solved the problem by redrawing the text only when I found that the wrap changes during resizing.

+2
source share
5 answers

Well, since no one seems to know what to do with this, I implemented it like this:

std::vector<std::wstring> wrapString(HDC hDC, const std::wstring& text, const RECT& targetRect, HFONT font) { std::vector<std::wstring> result; RECT targetRectangle; CopyRect(&targetRectangle, &targetRect); //Calculate the width of the bounding rectangle. int maxWidth = targetRectangle.right - targetRectangle.left; //Draw the lines one at a time std::wstring currentLine; for(std::wstring::const_iterator it = text.begin(); it != text.end(); currentLine.push_back(*it), it++) { if(*it == L'\r' || *it == L'\n') { //Hard return while(it != text.end() && (*it == L'\r' || *it == L'\n')) it++; result.push_back(currentLine); currentLine.clear(); } else { //Check for soft return SIZE sizeStruct; GetTextExtentPoint32(hDC, currentLine.c_str(), static_cast<int>(currentLine.length()), &sizeStruct); if (sizeStruct.cx > maxWidth) { std::wstring::size_type lineLength = currentLine.find_last_of(L' '); if (lineLength == currentLine.npos) { //Word is longer than a line. for(;it != text.end() && !iswspace(*it);it++) currentLine.push_back(*it); } else { //Clip word to line. //Backtrack our scan of the source text. it -= currentLine.length() - lineLength - 1; //Remove the clipped word currentLine.erase(lineLength); } result.push_back(currentLine); currentLine.clear(); } } } //Last remaining text. result.push_back(currentLine); return result; } void DrawInstructionsWithFilledBackground(HDC hDC, const std::wstring& text, RECT& targetRectangle, HFONT font, COLORREF backgroundColor) { //Set up our background color. int dcIdx = SaveDC(hDC); HBRUSH backgroundBrush = CreateSolidBrush(backgroundColor); SelectObject(hDC, backgroundBrush); SelectObject(hDC, font); SetBkColor(hDC, backgroundColor); std::vector<std::wstring> lines(wrapString(hDC, text, targetRectangle, font)); for(std::vector<std::wstring>::const_iterator it = lines.begin(); it!=lines.end(); it++) { RECT backgroundRect = targetRectangle; DrawText(hDC, const_cast<LPWSTR>(it->c_str()), static_cast<int>(it->length()), &backgroundRect, DT_CALCRECT | DT_NOCLIP | DT_SINGLELINE); backgroundRect.left = backgroundRect.right; backgroundRect.right = targetRectangle.right; if (backgroundRect.right >= backgroundRect.left) FillRect(hDC, &backgroundRect, backgroundBrush); ExtTextOut(hDC, targetRectangle.left, targetRectangle.top, ETO_OPAQUE, NULL, it->c_str(), static_cast<UINT>(it->length()), NULL); targetRectangle.top += backgroundRect.bottom - backgroundRect.top; } instructionsWrap = lines; //Restore the DC to it former glory. RestoreDC(hDC, dcIdx); DeleteObject(backgroundBrush); } 
+2
source

Use double buffering?

Draw everything into a bitmap and draw a bitmap in the window. Flickering is usually a double buffering problem.

+4
source

There are many possible solutions, and without seeing your code, it is difficult to say which method will be better, so I would like to look at this article in the drawing without flickering

+2
source

SetBkMode + SetBkColor?

+2
source

Get / compute the rectangle used by the DrawText call and copy it using something like ExcludeClipRect before calling FillRect

-1
source

All Articles