66.2.1 Using Regions to Clip Output

This section contains a single example that demonstrates how you can use regions to let the user define a part of the client area in which output can appear. When regions are used for this purpose, they are called clipping regions.

The example code for this section is taken from a Windows application that lets a user to capture the entire desktop as a bitmap and then isolate and save a part of this image as a .bmp file. The following illustration shows the application's window, menu, and client area immediately after the user captured the current desktop contents:

Sample Application

By selecting the Define Clip-Region option, the user is able to select a clip region by clicking the left mouse button and dragging the mouse. As the user drags the mouse, the application draws a rectangle that corresponds to the new clip region. The following illustration shows the application's window, client area, and the rectangle created by the user:

Clip-Region Definition

By selecting the Clip option, the user is able to redraw the isolated part of the image within the boundaries of the specified rectangle. The following illustration shows the application's window, client area, and the clipped output:

Clipped Output

66.2.1.1 Defining the Clip-Region

When the user chooses the Define Clip-Region option, Windows issues a WM_COMMAND message. The wParam parameter of this message contains an application-defined constant, IDM_DEFINE, which indicates that the user chose this option from the menu. The application processes this input by setting a boolean flag, fDefineRegion, as shown below:

case WM_COMMAND:

switch(wParam) {

case IDM_DEFINE:

fDefineRegion = TRUE;

break;

Once the user has chosen the Define Clip-Region option, they can begin drawing the rectangle by pressing the left mouse button when the cursor is in the application's client area and dragging the mouse.

When the user presses the left button, Windows issues a WM_LBUTTONDOWN message. The lParam parameter of this message contains the coordinates of the cursor. These coordinates correspond to the upper left corner of a rectangle that will be used to define the clip region. The application processes the WM_LBUTTONDOWN message as shown below:

/* These variables are required for clipping */

static POINT ptUpperLeft;

static POINT ptLowerRight;

static POINT aptRect[5];

static POINT ptTmp;

static POINTS ptsTmp;

static BOOL fDefineRegion;

static BOOL fRegionExists;

static HRGN hrgn;

static RECT rctTmp;

int i;

switch (message) {

case WM_LBUTTONDOWN:

if (fDefineRegion){

/* Retrieve the new upper-left corner */

ptsTmp = MAKEPOINTS(lParam);

ptUpperLeft.x = (LONG)ptsTmp.x;

ptUpperLeft.y = (LONG)ptsTmp.y;

}

if (fRegionExists){

/* erase the previous rectangle */

hdc = GetDC(hwnd);

SetROP2(hdc, R2_NOTXORPEN);

if (!Polyline(hdc, (CONST POINT *)aptRect, 5))

errhandler("Polyline Failed", hwnd);

ReleaseDC(hwnd, hdc);

/* clear the rectangle coordinates. */

for (i=0; i<4; i++){

aptRect[i].x = 0;

aptRect[i].y = 0;

}

/* clear the temporary point structure. */

ptTmp.x = 0;

ptTmp.y = 0;

/* clear the lower right-hand coordinates. */

ptLowerRight.x = 0;

ptLowerRight.y = 0;

/* reset the flag. */

fRegionExists = FALSE;

fDefineRegion = TRUE;

/* Retrieve the new upper-left corner */

ptsTmp = MAKEPOINTS(lParam);

ptUpperLeft.x = (LONG)ptsTmp.x;

ptUpperLeft.y = (LONG)ptsTmp.y;

}

break;

As the user drags the mouse, Windows issues WM_MOUSEMOVE messages and stores the new cursor coordinates in the lParam parameter. Each time the application receives a new WM_MOUSEMOVE message, it erases the previous rectangle (if one exists) and draws the new rectangle by calling the Polyline function and passing the coordinates of the four corners of the rectangle. The application performs these tasks as shown below:

/* These variables are required for clipping */

static POINT ptUpperLeft;

static POINT ptLowerRight;

static POINT aptRect[5];

static POINT ptTmp;

static POINTS ptsTmp;

static BOOL fDefineRegion;

static BOOL fRegionExists;

static HRGN hrgn;

static RECT rctTmp;

int i;

switch (message) {

case WM_MOUSEMOVE:

if (wParam & MK_LBUTTON && fDefineRegion){

/* Get a window DC. */

hdc = GetDC(hwnd);

if (!SetROP2(hdc, R2_NOTXORPEN))

errhandler("SetROP2 Failed", hwnd);

/* If previous mouse movement occurred, store the original */

/* lower-right corner coordinates in a temporary structure. */

if (ptLowerRight.x){

ptTmp.x = ptLowerRight.x;

ptTmp.y = ptLowerRight.y;

}

/* Get the new coordinates of the clipping-region's lower */

/* right-hand corner. */

ptsTmp = MAKEPOINTS(lParam);

ptLowerRight.x = (LONG)ptsTmp.x;

ptLowerRight.y = (LONG)ptsTmp.y;

/* If previous mouse movement occurred, erase the original */

/* rectangle. */

if (ptTmp.x){

aptRect[0].x = ptUpperLeft.x;

aptRect[0].y = ptUpperLeft.y;

aptRect[1].x = ptTmp.x;

aptRect[1].y = ptUpperLeft.y;

aptRect[2].x = ptTmp.x;

aptRect[2].y = ptTmp.y;

aptRect[3].x = ptUpperLeft.x;

aptRect[3].y = ptTmp.y;

aptRect[4].x = aptRect[0].x;

aptRect[4].y = aptRect[0].y;

if (!Polyline(hdc, (CONST POINT *)aptRect, 5))

errhandler("Polyline Failed", hwnd);

}

aptRect[0].x = ptUpperLeft.x;

aptRect[0].y = ptUpperLeft.y;

aptRect[1].x = ptLowerRight.x;

aptRect[1].y = ptUpperLeft.y;

aptRect[2].x = ptLowerRight.x;

aptRect[2].y = ptLowerRight.y;

aptRect[3].x = ptUpperLeft.x;

aptRect[3].y = ptLowerRight.y;

aptRect[4].x = aptRect[0].x;

aptRect[4].y = aptRect[0].y;

if (!Polyline(hdc, (CONST POINT *)aptRect, 5))

errhandler("Polyline Failed", hwnd);

ReleaseDC(hwnd, hdc);

}

break;

66.2.1.2 Clipping Output

Once the user chooses the Clip option from the menu, the application uses the coordinates of the rectangle that the user created to define a clip region. After defining the clip region and selecting it into the application's device context, the application redraws the bitmapped image. The application performs these tasks as shown below:

/* These variables are required for clipping */

static POINT ptUpperLeft;

static POINT ptLowerRight;

static POINT aptRect[5];

static POINT ptTmp;

static POINTS ptsTmp;

static BOOL fDefineRegion;

static BOOL fRegionExists;

static HRGN hrgn;

static RECT rctTmp;

int i;

case WM_COMMAND:

switch(wParam) {

case IDM_CLIP:

hdc = GetDC(hwnd);

/* Retrieve the app's client rectangle and paint with */

/* default (white) brush. */

GetClientRect(hwnd, &rctTmp);

FillRect(hdc, &rctTmp, GetStockObject(WHITE_BRUSH));

/* Use the rectangle coordinates to define a clip region. */

hrgn = CreateRectRgn(aptRect[0].x, aptRect[0].y, aptRect[2].x, aptRect[2].y);

SelectClipRgn(hdc, hrgn);

/* Draw the bitmap into the clipped rectangle */

BitBlt(hdc,

0,0,

bmp.bmWidth, bmp.bmHeight,

hdcCompatible,

0,0,

SRCCOPY);

ReleaseDC(hwnd, hdc);

break;