Introduction
Beginning with Visual C++ .NET 7.0, CPoint
, CRect
, CSize
, CString
, CImage
classes have been written to be library-independent. These classes can be
used in either MFC or ATL projects, or in projects that do not use either
of these libraries.
This article presents an application called SharedClasses that is a Win32 Project generated by the AppWizard. The application handles mouse input and draws an ellipse based on the mouse movement. The shared MFC/ATL classes are used throughout the application.
The demo app
To draw the ellipse press the left mouse button (it will be the center
of the ellipse) and move the mouse while holding the button. The status
line at the top of the window shows the center coordinates and the
ellipse's dimension (width and height).
The AppWizard generate an application that implements simple window. To
add new functionality we have to modify window the procedure (WndProc)
function.
We will be using the CString
and CRect
classes, so to add support for it
we need to include the following headers:
#include <atltypes.h> // CPoint, CRect, CSize support.
#include <atlstr.h> // CString support.
we also need to include Windowsx.h to use GET_X_LPARAM
and GET_Y_LPARAM
macros.
#include <Windowsx.h> // GET_X_LPARAM and GET_Y_LPARAM defined there.
To track mouse input let's add a CRect
type variable.
CRect rectEllipse;
To keep status line text we use a CString
class.
CString strCoord;
We also need a flag to keep the state of the left mouse button.
bool bLBtnPressed = false;
To track the mouse input we handle three windows messages: WM_LBUTTONDOWN
, WM_LBUTTONUP
, and WM_MOUSEMOVE
.
Just add following code to the end of switch statement inside WndProc
, just
before the default label:
case WM_LBUTTONDOWN:
rectEllipse.left = GET_X_LPARAM(lParam);
rectEllipse.top = GET_Y_LPARAM(lParam);
bLBtnPressed = true;
::SetCapture(hWnd);
break;
case WM_LBUTTONUP:
bLBtnPressed = false;
::ReleaseCapture();
::InvalidateRect(hWnd, NULL, TRUE);
::UpdateWindow(hWnd);
break;
case WM_MOUSEMOVE:
if(bLBtnPressed)
{
rectEllipse.right = GET_X_LPARAM(lParam);
rectEllipse.bottom = GET_Y_LPARAM(lParam);
::InvalidateRect(hWnd, NULL, TRUE);
::UpdateWindow(hWnd);
}
break;
In the WM_LBUTTONDOWN
message handler we store the coordinates of the point
where the user pressed the left mouse button. This will be the center of our
ellipse. We set the flag that stores mouse button state and capture the mouse
input so as to handle mouse input even when it is outside the window.
The WM_MOUSEMOVE
message handler checks the state of the mouse button. If it
is pressed it updates our rectangle (our CRect
class object) with the new mouse
coordinates and redraws the window. If the mouse button is not pressed, it does
nothing.
In the WM_LBUTTONUP
handler we just update the flag that keeps the mouse button
state and release the mouse capture. Inside it just draws the ellipse according
to the coordinates stored in the CRect
object and formats and prints a status
string to show information for the ellipse, namely center coordinates and dimensions.
In order to draw our ellipse we have to modify WM_PAINT
message handler:
::Ellipse( hdc,
rectEllipse.left - rectEllipse.Width(),
rectEllipse.top - rectEllipse.Height(),
rectEllipse.left + rectEllipse.Width(),
rectEllipse.top + rectEllipse.Height());
if(rectEllipse.Width() != 0 && rectEllipse.Height() != 0)
{
strCoord.Format(_T("Center coordinates %d,%d X-size %d, Y-Size %d"),
rectEllipse.left,
rectEllipse.top,
2 * rectEllipse.Width(),
2 * rectEllipse.Height());
}
else
strCoord = _T("Use your mouse to draw ellipse in the window");
::TextOut(hdc, 5, 5 , strCoord, strCoord.GetLength());
History
16 Oct 2001 - updated files for VS beta 2