我正在编写Scribble教程以学习MFC,并且MouseMove事件中有以下代码:
void CScribbleView::OnMouseMove(UINT nFlags, CPoint point)
{
// Mouse movement is interesting in the Scribble application
// only if the user is currently drawing a new stroke by
// dragging the captured mouse.
if( GetCapture( ) != this )
return; // If this window (view) didn't capture the
// mouse, the user isn't drawing in this window.
// Add the new point to the current stroke
m_pStrokeCur->m_pointArray.Add(point);
CClientDC dc( this );
// Draw a line from the previous detected point in the mouse
// drag to the current point.
CPen* pOldPen =
dc.SelectObject( GetDocument( )->GetCurrentPen( ) );
dc.MoveTo( m_ptPrev );
dc.LineTo( point );
dc.SelectObject( pOldPen );
m_ptPrev = point;
CView::OnMouseMove(nFlags, point);
}
这个关于笔画的绘制函数(由视图的OnDraw调用):
BOOL CStroke::DrawStroke( CDC* pDC )
{
CPen penStroke;
if( !penStroke.CreatePen(PS_SOLID, m_nPenWidth, RGB(0,0,0)))
return FALSE;
CPen* pOldPen = pDC->SelectObject( &penStroke );
pDC->MoveTo( m_pointArray[0] );
for( int i=1; i < m_pointArray.GetSize(); i++ )
{
pDC->LineTo( m_pointArray[i] );
}
pDC->SelectObject( pOldPen );
return TRUE;
}
我已经检查过每次帧更新都会调用此函数。但是,如果我取消鼠标移动事件的绘图,即使我正在注册所有笔划并且正在调用绘图笔划功能,它也不会发生任何事情。只有当我对窗口进行更改(如最大化)时才会出现。如果函数
正在调用,为什么不在窗口上画画?我试图在这里找出MFC的内部工作原理,它不是一个bug或任何东西。
答案 0 :(得分:2)
当您的全部或部分窗口已过期(称为“无效”)时,消息循环将最终收到两条消息:WM_ERASEBKGND,然后是WM_PAINT。 Windows应用程序绘制的典型方法是在WM_ERASEBKGND和WM_PAINT处理程序中绘制所有内容。 (我不是MFC专家,但我相信WM_PAINT对应于MFC中的OnDraw。)
因此处理此问题的常用方法是让鼠标移动处理程序记录笔划(就像它一样),然后将窗口标记为无效。这最终会导致线条被绘制。但是,可能会有轻微的延迟,并可能导致闪烁。在现代计算机上延迟可能是微不足道的(但是Scribble很旧)。处理闪烁有多种方法。
Scribble作者似乎选择通过直接在鼠标移动处理程序中绘制直线来处理延迟和闪烁,而不是使窗口无效并让OnDraw稍后执行。
失效是关键。您从OnMouseMove中删除了图形,因此不会在那里绘制线条。但是没有什么可以告诉Windows窗口内容现在已经过时(无效),因此它不会获得WM_PAINT消息,并且OnDraw不会被调用。 (稍后,当您执行诸如调整大小或最大化窗口之类的操作时,会使其无效,并且会调用OnDraw并突然显示该行。)
如果要从OnMouseMove中删除图形,则必须将其替换为InvalidateRect调用。这将告诉Windows窗口需要重新绘制。