我正在写一个mfc应用程序。
我有CWnd
和OnEraseBkgnd
的简单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);
下面窗口如何正常显示:
在移动窗口后下方,因此文本的一半没有显示,然后移回:
因此,不可见的窗口部分被删除,然后再次放置文本。对于窗口的可见部分,文本未被删除,并且OnPaint
再次重新绘制,导致&#39;粗体&#39;。
答案 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);
}