2009-12-02 52 views
2

我在Win32下有一个小小的文字绘图拼图。我试图在窗口顶部为我的应用程序的用户绘制一些说明。Win32文本绘图拼图

请参考下面的窗口(我已经改变背景颜色上的文本,所以你可以看到边界)

Demonstration http://billy-oneal.com/forums/12-2-2009%203-46-15%20PM.png

我目前使用DrawTextEx的文字画到我的窗口,但问题是它不会填充我给出的整个RECTangle。没有绘制区域仅仅是罚款,直至调整窗口大小:

Demonstration after resize http://billy-oneal.com/forums/12-2-2009%203-51-45%20PM.png

当文本被重新包装,由于窗口大小,因为DrawTextEx并不清楚它的背景下,这些文物是剩。

我试着使用FillRect来填充文本绘图调用后面的区域,它消除了视觉伪影,但随后会导致文本不断闪烁,因为它会被完全擦除,然后完全重新绘制到显示中。

关于如何让不包含文本的区域用背景颜色绘制的任何想法?

编辑:我想避免必须双缓冲窗体,如果在应用程序可能。

EDIT2:我在重新调整大小期间检测到包装发生变化时,通过重绘文本解决了问题。

+0

ExtTextOut + ETO_OPAQUE(https://msdn.microsoft.com/en-us/library/dd162713(v=vs.85).aspx) – 2017-02-26 10:46:01

回答

2

好,因为似乎没有人知道该怎么做这件事之前,像ExcludeClipRect夹它,我实现了这种方式:

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's former glory. 
    RestoreDC(hDC, dcIdx); 
    DeleteObject(backgroundBrush); 
} 
4

使用双缓冲?

将一切都绘制到位图并将位图绘制到窗口。闪烁通常是一个双缓冲问题。

+0

这将工作,但我想避免必须加倍缓冲一切进行如此简单的操作。我在应用程序的其余部分非常努力地工作,不需要双缓冲区。看起来很遗憾,为了这么简单的事情而浪费一切。 – 2009-12-02 21:03:53

+0

CPU是有限的资源还是内存?在前者的情况下,你可以对*当更新窗口时的限制性很强,即不多于每40ms更新一次。如果内存是你有限的资源,我想我们需要更多地了解你的硬件限制来解决你的问题。 – Pedery 2009-12-02 21:17:18

2

有许多可能的解决方案,并没有看到你的代码,这是很难说哪一种方法是最好的,所以我会建议考虑看看this article on flicker free drawing

+0

我读过那篇文章 - 其他应用程序遵循指南。文本是唯一闪烁的东西。其他一切都很好。 – 2009-12-02 21:08:04

+0

你的意思是一个常量闪烁,或者只是在调整大小? – BarrettJ 2009-12-02 21:23:23

+0

仅在调整大小时。 – 2009-12-02 23:56:41

2

SetBkMode + SetBkColor?

+0

正确地在背后绘制背景。我需要一种方法让函数在每行的左侧绘制背景以填充指令所在的矩形。 – 2009-12-02 21:11:32

-1

获取/计算由DrawText的调用中使用的矩形,并调用FillRect

+1

获取/计算DrawText使用的矩形< - 照顾我如何将不规则形状表示为RECT? – 2009-12-02 23:57:29

+0

你已经有一个RECT,你传递给DrawText(首先用DT_CALCRECT或一些“硬编码”值调用它) – Anders 2009-12-03 08:29:44