Saturday, October 24, 2009

28.1 Mouse messages



[ Team LiB ]










28.1 Mouse messages



Processing a mouse message


Windows generates a number of mouse-related messages, including WM_MOUSEMOVE and WM_ONLBUTTONDOWN. MFC handles these two with message handlers normally called OnMouseMove
and OnLButtonDown.


The programmer is free to decide which class is to hold the handler methods. One way to do this is to open the Class View and to right click on the name of class that is supposed to handle the mouse message. In Visual Studio.NET you then select Properties... and click on the Message button in the Properties dialog. (In Version 6.0, you right click the class and select Add Windows Message Handler....)


In any case, the default message handler you'll get for WM_MOUSEMOVE will look like this.



void CPopView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CView::OnMouseMove(nFlags, point);
}

We override this as follows, telling the view to pass the mouse click right on to the game object.



void CPopView::OnLButtonDown(UINT nFlags, CPoint point)
{
//My Code. RR.
SetCapture(); /* This is so that as long as the mouse button is
down, this window gets messages from the mouse even when the
mouse is outside the window. */
pgame()->onLButtonDown(this, nFlags, point);
/* Don't need to figure out the game world pos, it's set as pgame()
>pbiota()->_cursorpos in OnSetCursor. */
}

Our special cGame::onLButtonDown
(cPopView *pview, UINT nFlags, cPointpoint) code figures out which critter you should think of as being closest to the click with a line like this: cCritter* pTouched = _pbiota->pickClosest (pview->pgraphics()->pixelToSightLine(point.x, point.y));. And then, depending on the type of cursor currently active, the cGame
does something to the pTouched critter. See the source later in this chapter for details.


We handle the OnMouseMove
case in a different way. The cPopView::SetCursor has code to figure out the game world position closest to the pick point that also lies in the plane of the player critter.



void CPopView::OnMouseMove(UINT nFlags, CPoint point)
{
/* Normally I track the cursor position in OnSetCursor, but this
method doesn't get called during dragging, so I need to do it
here */
if ((nFlags & MK_LBUTTON) || (nFlags & MK_RBUTTON) ) //You're
dragging.
pgame()->setCursorPos(pixelToPlayerPlaneVector(point.x,
point.y));
pgame()->onMouseMove(this, nFlags, point);
}


Calling the OnDraw method


Often a mouse action changes the world in such a way that we need to redisplay it. This isn't an issue in our animated Pop framework, where the world is constantly being redisplayed. But in other programs it is an issue. The way to force a redisplay of all view windows from a given view's method is a line of the form pDoc->UpdateAllViews(NULL). You never try to call OnDraw
directly, as this is a severe Windows no-no. One reason is that we'd have to do too much work in getting the right kind of CDC *pDC ready for the OnDraw
argument, but there's some other considerations as well (which we won't go into).


No, the way to have, say, an OnMouseMove
call OnDraw
is to use an indirect approach. We call the Invalidate()
function. But in order to keep our Document-View architecture smoothly functioning, we're not going to let OnMouseMove
call Invalidate
directly. Instead we're going to go all around Robin Hood's barn and do this.



  • CPopView::OnMouseMove
    might kill off a critter say, and then call


  • CPopDoc::UpdateAllViews, which calls


  • CPopView::OnUpdate, which calls


  • CPopView::Invalidate, which calls


  • CPopView::OnDraw
    to draw the new state of affairs.



The pDoc->UpdateAllViews(NULL) line in the code has the default effect of telling the CPopDoc
to send an UpdateView
call to each of its views.


What about the CPopView::OnUpdate
method? As it turns out, the default CView
behavior for the method is just what you'd want; to call the Invalidate()
method.






    [ Team LiB ]



    No comments:

    Post a Comment