OnEraseBkgnd的剪切区域与OnPaint

时间:2015-11-27 14:10:34

标签: mfc

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

因此,当移出覆盖窗口时,我的CWnd会获得WM_ERASEBKGND。我正在清理肮脏的区域,然后我返回TRUE。我在这里看到的是CDC我得到了剪辑框设置并且我使用它,因此只有被覆盖的部分被删除。这很好。

然后WM_PAINT来了。 CDC我得到GetDC 没有有任何剪切框,因此整个窗口区域正在重新绘制。这是一个问题,因为在我的绘画事件中,我使用CDC::DrawText具有透明背景(CDC::SetBkMode(TRANSPARENT))并在同一个未删除的地方绘制相同的文字会导致该文字变为粗体&#39 ;。只需在同一个地方一遍又一遍地绘制文字而不消除背景,就会让它看起来很难看。

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

修改

在这里,我附上了更多关于问题的信息。

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()
};

创建:

Foo* f = new Foo;
f->Create( 0, "test", WS_VISIBLE| WS_OVERLAPPEDWINDOW);

下面窗口如何正常显示:

normal

在移动窗口后下方,因此文本的一半没有显示,然后移回:

not quite normal

因此,不可见的窗口部分被删除,然后再次放置文本。对于窗口的可见部分,文本未被删除,并且OnPaint再次重新绘制,导致&#39;粗体&#39;。

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

这是无关的问题,但GetDC导致上述代码中的GDI资源泄漏。退出函数前必须调用ReleaseDC

void OnPaint()
{
    CWnd::OnPaint();
    CDC *dc = GetDC();
    dc.DrawText(...);
    ...
    ReleaseDC(dc);
}

更好的是,MFC使用CClientDC

进行自动清理
void myWnd::foo()
{
    CClientDC dc(this);
    dc.DrawText(...);
}

OnPaint可以使用与CPaintDC对应的特殊PAINTSTRUCT类:

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()

中的所有绘画
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);
}