When storing the coordinates of strokes, Scribble needs to know where the strokes are relative to the document, not relative to the client area. Consequently, CScribbleView
must convert points from device coordinates (relative to the window origin) to logical coordinates (relative to the document origin) before storing them in CStroke
objects.
To store the strokes using logical coordinates
OnLButtonDown
member function of class CScribbleView
in ScribbleView.cpp and add the following code to the beginning of the function definition: // CScrollView changes the viewport origin and mapping mode.
// It's necessary to convert the point from device coordinates
// to logical coordinates, such as are stored in the document.
CClientDC dc(this);
OnPrepareDC(&dc); // set up mapping mode and viewport origin
dc.DPtoLP(&point);
In this function, the view receives a point specified in device coordinates. A device context is needed to find the GDI origin, so the function declares a CClientDC object, which is a CDC object for the client area of the view, and calls OnPrepareDC to adjust its origin. Then the function passes the point to the DPtoLP (Device Point to Logical Point) member function of CDC to perform the actual conversion. The point added to m_pStrokeCur
is thus described in logical coordinates (that is, relative to the document origin).
OnMouseMove
and add similar code just after the line CClientDC dc(this)
:// CScrollView changes the viewport origin and mapping mode.
// It's necessary to convert the point from device coordinates
// to logical coordinates, such as are stored in the document.
OnPrepareDC(&dc); // set up mapping mode and viewport origin
dc.DPtoLP(&point);
This function already has a device context for drawing the stroke in progress, so the only modifications needed are to call OnPrepareDC to move the viewport origin and then DPtoLP to convert the point before adding it.
OnLButtonUp
member function, again, just after the line CClientDC dc(this)
:// CScrollView changes the viewport origin and mapping mode.
// It's necessary to convert the point from device coordinates
// to logical coordinates, such as are stored in the document.
OnPrepareDC(&dc); // set up mapping mode and viewport origin
dc.DPtoLP(&point);
Like OnMouseMove
, this function already has a device context to complete drawing the stroke, so the only modifications needed are to call OnPrepareDC and then DPtoLP.
OnUpdate
and add the following lines of code just after the line CStroke* pStroke = (CStroke*)pHint:
CClientDC dc(this);
OnPrepareDC(&dc);
CRect rectInvalid
... line) and add the following line:dc.LPtoDP(&rectInvalid);
Unlike the previous three functions, OnUpdate
requires a conversion in the opposite direction; that is, from logical coordinates to device coordinates. Recall that OnUpdate
retrieves the bounding rectangle of a stroke and invalidates that rectangle. The stroke’s bounding rectangle is stored in logical coordinates. However, the rectangle passed to InvalidateRect must be specified in device coordinates (since InvalidateRect is not a GDI function). Accordingly, a stroke’s bounding rectangle must have its coordinates converted into device coordinates before it can be invalidated.
The function declares a CClientDC object and then calls the OnPrepareDC member function to move the viewport origin of the device context to reflect the currently scrolled position. The rectangle is then passed to the LPtoDP (Logical Point to Device Point) function of CDC to convert its points into device coordinates. (Both DPtoLP and LPtoDP are overloaded to accept rectangles as well as points.) Once it is converted, the rectangle can be invalidated.
Note This is a good point to compile and test Scribble’s scrolling.