6.3.1 Starting a Graphics Selection

Because graphics can be virtually any shape, they are potentially more difficult to select than simple text. The simplest approach to selecting graphics is to let the user “stretch” a selection rectangle so that it encloses the desired information.

This section explains how to use the “rubber rectangle” method of selecting graphics. You can use the WM_LBUTTONDOWN, WM_LBUTTONUP, and WM_MOUSEMOVE messages to create the rectangle. This lets the user create the selection by choosing a point, pressing the left mouse button, and dragging to another point before releasing. As the user drags the mouse, your application can provide instant feedback by inverting the border of the rectangle described by the starting and current points.

For this method, the application starts the selection upon receiving the WM_LBUTTONDOWN message. The application must then do three things: capture the mouse input, save the starting (original) point, and save the current point, as follows:

BOOL fTrack = FALSE;   /* global variables */
int OrgX = 0, OrgY = 0;
int PrevX = 0, PrevY = 0;
    .
    .
    .

case WM_LBUTTONDOWN:
    fTrack = TRUE;
    PrevX = LOWORD(lParam);
    PrevY = HIWORD(lParam);
    OrgX = LOWORD(lParam);
    OrgY = HIWORD(lParam);
    InvalidateRect(hWnd, NULL, TRUE);
    UpdateWindow(hWnd);

    /* Capture all input even if mouse goes outside window. */

    SetCapture(hWnd);
    break;

When the application receives the WM_LBUTTONDOWN message, the fTrack variable is set to TRUE to indicate that a selection is in progress. As with any mouse message, the lParam parameter contains the current x- and y-coordinates of the mouse in the low and high-order words, respectively. These are saved as the origin x and y values, OrgX and OrgY, as well as the previous values, PrevX and PrevY. The PrevX and PrevY variables will be updated immediately when the next WM_MOUSEMOVE message is received. The OrgX and OrgY variables remain unchanged and will be used to determine a corner of the bitmap to be copied. (The variables fTrack, OrgX, OrgY, PrevX, and PrevY must be global variables.)

To provide immediate visual feedback in response to the WM_LBUTTONDOWN message, the application invalidates the screen and notifies the window procedure that it must repaint the screen. The application does this by calling the functions InvalidateRect and UpdateWindow.

The SetCapture function directs all subsequent mouse input to the window even if the cursor moves outside of the window. This ensures that the selection process will continue uninterrupted.

Your application should respond to the WM_PAINT message by redrawing the invalidated portions of the screen, as in the following example:

case WM_PAINT:
    {
        PAINTSTRUCT     ps;
        HDC             hDC;

        hDC = BeginPaint(hWnd, &ps);
        if (OrgX != PrevX || OrgY != PrevY) {
            MoveTo(hDC, OrgX, OrgY);
            LineTo(hDC, OrgX, PrevY);
            LineTo(hDC, PrevX, PrevY);
            LineTo(hDC, PrevX, OrgY);
            LineTo(hDC, OrgX, OrgY);
        }
        EndPaint(hWnd, &ps);
    }
    break;