Mfc OnEraseBkgnd的剪裁区域与OnPaint的剪裁区域不同

Mfc OnEraseBkgnd的剪裁区域与OnPaint的剪裁区域不同,mfc,Mfc,我正在写一个mfc应用程序。 我有一个简单的CWnd,带有OnEraseBkgnd和OnPaint。当另一个窗口部分覆盖我的窗口时,我遇到一些问题 因此,当覆盖窗口移出时,myCWnd会获得WM_ERASEBKGND。我正在清理脏区域,返回TRUE。我在这里看到的是,CDC我得到了一个剪辑框,我使用它,所以只有一个被覆盖的部分被擦除。那很好 但是随后WM_PAINT来了CDCGetDC没有任何剪辑框,因此正在重新绘制整个窗口区域。这是一个问题,因为在我的绘制事件中,我使用透明背景(CDC::Se

我正在写一个mfc应用程序。 我有一个简单的
CWnd
,带有
OnEraseBkgnd
OnPaint
。当另一个窗口部分覆盖我的窗口时,我遇到一些问题

因此,当覆盖窗口移出时,my
CWnd
会获得
WM_ERASEBKGND
。我正在清理脏区域,返回
TRUE
。我在这里看到的是,
CDC
我得到了一个剪辑框,我使用它,所以只有一个被覆盖的部分被擦除。那很好

但是随后
WM_PAINT
来了
CDC
GetDC没有任何剪辑框,因此正在重新绘制整个窗口区域。这是一个问题,因为在我的绘制事件中,我使用透明背景(
CDC::SetBkMode(transparent)
)的
CDC::DrawText
),并且在相同的未擦除位置绘制相同的文本会导致文本变为“粗体”。简单地在同一个地方一遍又一遍地绘制文本而不清除背景会使其看起来很难看

这是正常的行为吗?我的方法行吗

编辑:

这里我附上更多关于这个问题的信息

SSCCE:

class Foo : public CFrameWnd
{
public:
    BOOL OnEraseBkgnd(CDC* pDC)
    {
        CRect rect;
        pDC->GetClipBox(rect);

        HBRUSH brush = ::GetSysColorBrush(COLOR_WINDOW);
        HGDIOBJ pOld = pDC->SelectObject(brush);

        const BOOL result = pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);

        pDC->SelectObject(pOld);

        return result;
    }

    void OnPaint()
    {
        CWnd::OnPaint();

        CDC *dc = GetDC();

        CRect clipBox;
        dc->GetClipBox(clipBox);

        CRect rect;
        GetClientRect(rect);

        CFont *font = &globalFont;                 // in my app here is the font I use but it doesn't matter
        HFONT hFont = static_cast<HFONT>(font->GetSafeHandle());

        auto oldFont = dc->SelectObject(hFont);
        const int bkMode = dc->SetBkMode(TRANSPARENT);               
        dc->DrawText("AAAAAAAAA", -1, rect, 0);
        dc->SetBkMode(bkMode);
        dc->SelectObject(oldFont);
    }

    DECLARE_MESSAGE_MAP()
};
下面是窗口的正常外观:

在移动窗口使一半文本离开监视器后,再移回以下位置:


因此,窗口中不可见的部分被删除,然后再次放置文本。对于窗口的可见部分,文本未被擦除,并且在
OnPaint
中再次被重绘,导致“粗体”。

这是一个无关的问题,但
GetDC
导致上述代码中的GDI资源泄漏<退出函数前必须调用代码>释放DC:

void OnPaint()
{
    CWnd::OnPaint();
    CDC *dc = GetDC();
    dc.DrawText(...);
    ...
    ReleaseDC(dc);
}
更好的是,MFC可以通过
CClientDC

void myWnd::foo()
{
    CClientDC dc(this);
    dc.DrawText(...);
}
OnPaint
可以使用与
PAINTSTRUCT
相对应的特殊
CPaintDC
类:

void myWnd::OnPaint()
{
    CPaintDC dc(this); //don't call CWnd::OnPaint
    dc.DrawText(...);
}
回到问题:

看起来部分背景没有重新绘制,但部分文本已重新绘制。这使得它看起来很难看,特别是使用清晰的字体(看起来像粗体,但不是)

您可以通过以下方法解决此问题:

dc.SetBkMode(OPAQUE);
dc.SetBkColor(GetSysColor(COLOR_WINDOW));
dc.DrawText(L"AAAAAAAAA", -1, rect, 0);
另一个选项:覆盖OnEraseBkgnd并强制其不执行任何操作:

BOOL OnEraseBkgnd(CDC*)
{
    return TRUE;
}
OnPaint()中进行所有绘制


您应该使用
CPaintDC
,这不仅是因为它控制资源,正如Barmak所指出的,而且还因为它检索剪辑数据
GetDC
不会这样做。(Barmak也提到了
PAINTSTRUCT
,但可能不清楚这是剪辑问题的关键。)

如果您提供更多信息,可能会有所帮助。此窗口和其他窗口(弹出窗口、子窗口等)的创建标志是什么?这个窗口和另一个窗口的父窗口是什么?它们之间的关系是什么关于某些文本变为粗体,可能与清晰的类型格式有关,它不会变为粗体,但文本会变得更重,因为您在上面书写时没有删除以前的文本。@BarmakShemirani我已经添加了代码和screenshotsThx作为答案,但我仍然不明白为什么它不能正常工作。我可以有变通办法,但我认为这不是重点。
BOOL OnEraseBkgnd(CDC*)
{
    return TRUE;
}
void myWnd::OnPaint()
{
    CPaintDC dc(this);

    CRect rect;
    GetClientRect(rect);
    dc.FillSolidRect(rect, ::GetSysColor(COLOR_WINDOW) );

    CFont *font = &globalFont;
    auto oldFont = dc.SelectObject(font->GetSafeHandle());
    dc.SetBkMode(TRANSPARENT);
    dc.DrawText(L"AAAAAAAAA", -1, rect, 0);

    dc.SelectObject(oldFont);
}