Text Win32文本绘图难题

Text Win32文本绘图难题,text,winapi,drawing,flicker,Text,Winapi,Drawing,Flicker,我在Win32下有一个小的文本绘制拼图。我试图在窗口顶部为我的应用程序的用户绘制一些说明 请参考以下窗口(我已更改文本的背景色,以便您可以看到边界) (来源:) 我目前正在使用DrawTextEx将文本绘制到我的窗口,但问题是它不能填充我给它的整个矩形。在窗口调整大小之前,不绘制该区域即可: (来源:) 当由于窗口大小而重新包装文本时,因为DrawTextEx没有清除其背景,这些工件是剩余的 我尝试使用FillRect填充文本绘制调用后面的区域,这确实消除了视觉瑕疵,但随后导致文本不断闪烁,

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

请参考以下窗口(我已更改文本的背景色,以便您可以看到边界)


(来源:)

我目前正在使用DrawTextEx将文本绘制到我的窗口,但问题是它不能填充我给它的整个矩形。在窗口调整大小之前,不绘制该区域即可:


(来源:)

当由于窗口大小而重新包装文本时,因为DrawTextEx没有清除其背景,这些工件是剩余的

我尝试使用FillRect填充文本绘制调用后面的区域,这确实消除了视觉瑕疵,但随后导致文本不断闪烁,因为它被完全擦除,然后完全重新绘制到显示中

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

编辑:如果可能的话,我想避免在应用程序中对表单进行双重缓冲

EDIT2:我解决了这个问题,当我检测到包装在调整大小过程中发生变化时,我只重新绘制文本。

使用双缓冲


将所有内容绘制为位图,并将位图绘制到窗口。闪烁通常是一个双缓冲问题。

有许多可能的解决方案,在没有看到代码的情况下,很难说哪种方法是最好的,所以我建议看一看

SetBkMode+SetBkColor?

获取/计算DrawText调用使用的rect,并在调用FillRect之前用excludeCliect之类的东西对其进行剪裁。既然似乎没有人知道如何处理,我就这样实现了它:

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);
}
std::vector wrapString(HDC HDC、const std::wstring和text、const RECT和targetect、HFONT字体)
{
std::向量结果;
直射靶射角;
CopyRect(&targetRectangle,&targetRect);
//计算边框的宽度。
int maxWidth=targetlectangle.right-targetlectangle.left;
//一次画一条线
std::wstring电流线;
对于(std::wstring::const_迭代器it=text.begin();it!=text.end();currentLine.push_back(*it),it++)
{
如果(*it==L'\r'| |*it==L'\n')
{//硬回
而(it!=text.end()&(*it==L'\r'| |*it==L'\n'))it++;
结果。推回(当前线路);
currentLine.clear();
}
其他的
{//检查是否存在软返回
大小和结构;
GetTextExtentPoint32(hDC、currentLine.c_str()、static_cast(currentLine.length())、和sizeStruct);
如果(sizeStruct.cx>maxWidth)
{
std::wstring::size_type lineLength=currentLine。查找(L'')中的最后一个;
if(lineLength==currentLine.npos)
{//单词比一行长。
对于(;it!=text.end()&&!iswspace(*it);it++)currentLine.push_back(*it);
}
其他的
{//将单词剪切到行。
//回溯我们对源文本的扫描。
it-=currentLine.length()-lineLength-1;
//删除删节的单词
currentLine.erase(线宽);
}
结果。推回(当前线路);
currentLine.clear();
}
}
}
//最后剩下的文本。
结果。推回(当前线路);
返回结果;
}
无效绘图说明,带填充背景(HDC HDC,常量标准::wstring&text,RECT&targetlectangle,HFONT字体,COLORREF backgroundColor)
{
//设置我们的背景色。
int dcIdx=SaveDC(hDC);
HBRUSH backgroundBrush=CreateSolidBrush(backgroundColor);
选择对象(hDC、背景笔刷);
选择对象(hDC、字体);
SetBkColor(hDC,backgroundColor);
标准::矢量线(包装字符串(hDC、文本、targetRectangle、字体));
对于(std::vector::const_迭代器it=lines.begin();it!=lines.end();it++)
{
RECT backgroundRect=targetlectangle;
DrawText(hDC、const_cast(it->c_str())、static_cast(it->length())、backgroundRect、DT_CALCRECT、DT_NOCLIP、DT|u SINGLELINE);
backgroundRect.left=backgroundRect.right;
backgroundRect.right=targetlectangle.right;
if(backgroundRect.right>=backgroundRect.left)
FillRect(hDC和backgroundRect、backgroundBrush);
ExtTextOut(hDC,targetlectangle.left,targetlectangle.top,ETO_不透明,NULL,it->c_str(),static_cast(it->length()),NULL);
targetRectangle.top+=backgroundRect.bottom-backgroundRect.top;
}
指令换行=行;
//让DC恢复昔日的荣耀。
恢复的数据中心(hDC、dcIdx);
删除对象(背景笔刷);
}

这会管用,但我不想为了这样一个简单的操作而将所有内容都加倍缓冲。我对应用程序的其余部分进行了非常努力的工作,不需要双重缓冲区。为了这么简单的事情浪费掉所有这些似乎是一种耻辱。CPU是有限的资源还是内存?对于前者,您可以非常严格地限制何时更新窗口,即不超过每40毫秒一次。如果内存是您有限的资源,我想我们需要更多地了解您的硬件限制来解决您的问题。文本是唯一闪烁的东西。其他一切都很好。你是指持续闪烁,还是仅在调整大小时才闪烁?背景正确地绘制在文本后面。我需要一种方法让函数也在每行的左侧绘制背景,以填充指令所在的矩形。获取/计算DrawText使用的rect您已经有了一个传递给DrawText的rect(首先用DT_CALCRECT或一些“硬编码”值调用它)ExtTextOut+ETO_不透明()