15,979
社区成员
发帖
与我相关
我的任务
分享
void CFirstSDIView::OnDraw(CDC* pDC)
{
pDC->SelectStockObject(GRAY_BRUSH);
pDC->Ellipse(CRect(10, 10, 100, 100));
}
void CFirstSDIView::OnPaint()
{
CPaintDC dc(this); // device context for painting
CView::OnPaint();
}
void CFirstSDIView::OnPaint()
{
CPaintDC dc(this); // device context for painting
OnDraw(&dc);
}
void CFirstSDIView::OnPaint()
{
CPaintDC dc(this); // device context for painting
CView::OnPaint();
}
CView::OnPaint()的源码是这样的:
void CView::OnPaint()
{
// standard paint routine
CPaintDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc);
}
所以相当于连续构造了两个CPaintDC 对象。CPaintDC 构造函数的源码:
CPaintDC::CPaintDC(CWnd* pWnd)
{
ASSERT_VALID(pWnd);
ASSERT(::IsWindow(pWnd->m_hWnd));
if (!Attach(::BeginPaint(m_hWnd = pWnd->m_hWnd, &m_ps)))
AfxThrowResourceException();
}
里面调用了全局的::BeginPaint,BeginPaint在MSDN上的解释如下:
This function prepares the specified window for painting and fills a PAINTSTRUCT structure with information about the painting.
The BeginPaint function sets the clipping region of the device context to exclude any area outside the update region.
The update region is set by the InvalidateRect function and by the system after sizing, moving, creating, scrolling, or any other operation that affects the client area.
Each call to BeginPaint must have a corresponding call to the EndPaint function.
所以相当于连续调用了两次::BeginPaint,而中间没有EndPaint 。MSDN强调了,这么用不允许的。
也就是要么就不添加OnPaint,就在OnDraw里面画。添加了OnPaint,就直接在OnPaint画。或者:
void CFirstSDIView::OnPaint()
{
CPaintDC dc(this); // device context for painting
//一些绘图代码
OnDraw(&dc);
}
void CChildView::OnPaint()
{
CPaintDC dc(this); // 用于绘制的设备上下文
// TODO: 在此处添加消息处理程序代码
// 不要为绘制消息而调用 CWnd::OnPaint()
}
注意最后一句,不要为绘制消息而调用 CWnd::OnPaint(),意思是不要调用基类的OnPaint(),为什么这样呢?先介绍一个容易被忽略的重要概念,重画区,举例说明,如果程序只要改变窗口中的一小块,调用方法invalidateRect(rc),其中rc就是重画区(经常翻译成失效区),在随后产生的OnPaint事件中即使程序重画了全部窗口,Windows系统也只把rc规定的重画区反映到屏幕上,其它部分不变。言规正传,CPaintDC dc(this)执行后会删除窗口重画区,基类的CView::OnPaint会再次调用CPaintDC dc(this),因为没有重画区,也就不起作用了,所以MFC向导提示“不要为绘制消息而调用 CWnd::OnPaint()”。
根据以上说明分析一下LZ的代码:
CPaintDC dc(this); // device context for painting
CView::OnPaint();
第一行,CPaintDC dc(this)已经删除了重画区,第二行CView::OnPaint()里面虽然调用了OnDraw,但因为没有重画区,反映不到屏幕上,所以不起作用。
另一段代码:
CPaintDC dc(this); // device context for painting
OnDraw(&dc);
在有重画区的窗口中建立的画图dc,所以OnDraw(&dc);能画出来。
再补充说明两点:
1、窗口建立时整个用户区都是重画区,所以能绘出所有元素。
2、重画窗口时先取重画区,然后判断要画的元素是否在重画区中,如果不在就不画,大大提高效率,当然这是高级绘图,显示比较复杂的界面,要求比较高时用。
// 取重画区
CRect rcClip;
dc.GetClipBox( rcClip );