Uso de pinceles
Puede usar un pincel para pintar el interior de prácticamente cualquier forma mediante una función de interfaz de dispositivo gráfico (GDI). Esto incluye los interiores de rectángulos, puntos suspensivos, polígonos y trazados. En función de los requisitos de la aplicación, puede usar un pincel sólido de un color especificado, un pincel de stock, un pincel de sombreado o un pincel de patrón.
Esta sección contiene ejemplos de código que muestran la creación de un cuadro de diálogo de pincel personalizado. El cuadro de diálogo contiene una cuadrícula que representa el mapa de bits que el sistema usa como pincel. Un usuario puede usar esta cuadrícula para crear un mapa de bits de pincel de patrones y, a continuación, ver el patrón personalizado haciendo clic en el botón Probar patrón .
En la ilustración siguiente se muestra un patrón creado mediante el cuadro de diálogo Pincel personalizado .
Para mostrar un cuadro de diálogo, primero debe crear una plantilla de cuadro de diálogo. La siguiente plantilla de cuadro de diálogo define el cuadro de diálogo Pincel personalizado .
CustBrush DIALOG 6, 18, 160, 118
STYLE WS_DLGFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "Custom Brush"
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "", IDD_GRID, "Static", SS_BLACKFRAME |
WS_CHILD, 3, 2, 83, 79
CONTROL "", IDD_RECT, "Static", SS_BLACKFRAME |
WS_CHILD, 96, 11, 57, 28
PUSHBUTTON "Test Pattern", IDD_PAINTRECT, 96, 47, 57, 14
PUSHBUTTON "OK", IDD_OK, 29, 98, 40, 14
PUSHBUTTON "Cancel", IDD_CANCEL, 92, 98, 40, 14
END
El cuadro de diálogo Pincel personalizado contiene cinco controles: una ventana de cuadrícula de mapa de bits, una ventana de visualización de patrones y tres botones de inserción, con la etiqueta Patrón de prueba, Aceptar y Cancelar. El botón de inserción Patrón de prueba permite al usuario ver el patrón. La plantilla de cuadro de diálogo especifica las dimensiones generales de la ventana del cuadro de diálogo, asigna un valor a cada control, especifica la ubicación de cada control, etc. Para obtener más información, vea Cuadros de diálogo.
Los valores de control de la plantilla del cuadro de diálogo son constantes que se han definido como se indica a continuación en el archivo de encabezado de la aplicación.
#define IDD_GRID 120
#define IDD_RECT 121
#define IDD_PAINTRECT 122
#define IDD_OK 123
#define IDD_CANCEL 124
Después de crear una plantilla de cuadro de diálogo e incluirla en el archivo de definición de recursos de la aplicación, debe escribir un procedimiento de diálogo. Este procedimiento procesa los mensajes que el sistema envía al cuadro de diálogo. El siguiente extracto del código fuente de una aplicación muestra el procedimiento de cuadro de diálogo para el cuadro de diálogo Pincel personalizado y las dos funciones definidas por la aplicación a las que llama.
BOOL CALLBACK BrushDlgProc( HWND hdlg, UINT message, LONG wParam,
LONG lParam)
{
static HWND hwndGrid; // grid-window control
static HWND hwndBrush; // pattern-brush control
static RECT rctGrid; // grid-window rectangle
static RECT rctBrush; // pattern-brush rectangle
static UINT bBrushBits[8]; // bitmap bits
static RECT rect[64]; // grid-cell array
static HBITMAP hbm; // bitmap handle
HBRUSH hbrush; // current brush
HBRUSH hbrushOld; // default brush
HRGN hrgnCell; // test-region handle
HDC hdc; // device context (DC) handle
int x, y, deltaX, deltaY; // drawing coordinates
POINTS ptlHit; // mouse coordinates
int i; // count variable
switch (message)
{
case WM_INITDIALOG:
// Retrieve a window handle for the grid-window and
// pattern-brush controls.
hwndGrid = GetDlgItem(hdlg, IDD_GRID);
hwndBrush = GetDlgItem(hdlg, IDD_RECT);
// Initialize the array of bits that defines the
// custom brush pattern with the value 1 to produce a
// solid white brush.
for (i=0; i<8; i++)
bBrushBits[i] = 0xFF;
// Retrieve dimensions for the grid-window and pattern-
// brush controls.
GetClientRect(hwndGrid, &rctGrid);
GetClientRect(hwndBrush, &rctBrush);
// Determine the width and height of a single cell.
deltaX = (rctGrid.right - rctGrid.left)/8;
deltaY = (rctGrid.bottom - rctGrid.top)/8;
// Initialize the array of cell rectangles.
for (y=rctGrid.top, i=0; y < rctGrid.bottom; y += deltaY)
{
for(x=rctGrid.left; x < (rctGrid.right - 8) && i < 64;
x += deltaX, i++)
{
rect[i].left = x; rect[i].top = y;
rect[i].right = x + deltaX;
rect[i].bottom = y + deltaY;
}
}
return FALSE;
case WM_PAINT:
// Draw the grid.
hdc = GetDC(hwndGrid);
for (i=rctGrid.left; i<rctGrid.right;
i+=(rctGrid.right - rctGrid.left)/8)
{
MoveToEx(hdc, i, rctGrid.top, NULL);
LineTo(hdc, i, rctGrid.bottom);
}
for (i=rctGrid.top; i<rctGrid.bottom;
i+=(rctGrid.bottom - rctGrid.top)/8)
{
MoveToEx(hdc, rctGrid.left, i, NULL);
LineTo(hdc, rctGrid.right, i);
}
ReleaseDC(hwndGrid, hdc);
return FALSE;
case WM_LBUTTONDOWN:
// Store the mouse coordinates in a POINT structure.
ptlHit = MAKEPOINTS((POINTS FAR *)lParam);
// Create a rectangular region with dimensions and
// coordinates that correspond to those of the grid
// window.
hrgnCell = CreateRectRgn(rctGrid.left, rctGrid.top,
rctGrid.right, rctGrid.bottom);
// Retrieve a window DC for the grid window.
hdc = GetDC(hwndGrid);
// Select the region into the DC.
SelectObject(hdc, hrgnCell);
// Test for a button click in the grid-window rectangle.
if (PtInRegion(hrgnCell, ptlHit.x, ptlHit.y))
{
// A button click occurred in the grid-window
// rectangle; isolate the cell in which it occurred.
for(i=0; i<64; i++)
{
DeleteObject(hrgnCell);
hrgnCell = CreateRectRgn(rect[i].left,
rect[i].top,
rect[i].right, rect[i].bottom);
if (PtInRegion(hrgnCell, ptlHit.x, ptlHit.y))
{
InvertRgn(hdc, hrgnCell);
// Set the appropriate brush bits.
if (i % 8 == 0)
bBrushBits[i/8] = bBrushBits[i/8] ^ 0x80;
else if (i % 8 == 1)
bBrushBits[i/8] = bBrushBits[i/8] ^ 0x40;
else if (i % 8 == 2)
bBrushBits[i/8] = bBrushBits[i/8] ^ 0x20;
else if (i % 8 == 3)
bBrushBits[i/8] = bBrushBits[i/8] ^ 0x10;
else if (i % 8 == 4)
bBrushBits[i/8] = bBrushBits[i/8] ^ 0x08;
else if (i % 8 == 5)
bBrushBits[i/8] = bBrushBits[i/8] ^ 0x04;
else if (i % 8 == 6)
bBrushBits[i/8] = bBrushBits[i/8] ^ 0x02;
else if (i % 8 == 7)
bBrushBits[i/8] = bBrushBits[i/8] ^ 0x01;
// Exit the "for" loop after the bit is set.
break;
} // end if
} // end for
} // end if
// Release the DC for the control.
ReleaseDC(hwndGrid, hdc);
return TRUE;
case WM_COMMAND:
switch (wParam)
{
case IDD_PAINTRECT:
hdc = GetDC(hwndBrush);
// Create a monochrome bitmap.
hbm = CreateBitmap(8, 8, 1, 1,
(LPBYTE)bBrushBits);
// Select the custom brush into the DC.
hbrush = CreatePatternBrush(hbm);
hbrushOld = SelectObject(hdc, hbrush);
// Use the custom brush to fill the rectangle.
Rectangle(hdc, rctBrush.left, rctBrush.top,
rctBrush.right, rctBrush.bottom);
// Clean up memory.
SelectObject(hdc, hbrushOld);
DeleteObject(hbrush);
DeleteObject(hbm);
ReleaseDC(hwndBrush, hdc);
return TRUE;
case IDD_OK:
case IDD_CANCEL:
EndDialog(hdlg, TRUE);
return TRUE;
} // end switch
break;
default:
return FALSE;
}
}
int GetStrLngth(LPTSTR cArray)
{
int i = 0;
while (cArray[i++] != 0);
return i-1;
}
DWORD RetrieveWidth(LPTSTR cArray, int iLength)
{
int i, iTmp;
double dVal, dCount;
dVal = 0.0;
dCount = (double)(iLength-1);
for (i=0; i<iLength; i++)
{
iTmp = cArray[i] - 0x30;
dVal = dVal + (((double)iTmp) * pow(10.0, dCount--));
}
return (DWORD)dVal;
}
El procedimiento de cuadro de diálogo del cuadro de diálogo Pincel personalizado procesa cuatro mensajes, como se describe en la tabla siguiente.
Message | Acción |
---|---|
WM_INITDIALOG | Recupera un identificador de ventana y dimensiones para los controles grid-window y pattern-brush, calcula las dimensiones de una sola celda en el control de ventana de cuadrícula e inicializa una matriz de coordenadas de celda de cuadrícula. |
WM_PAINT | Dibuja el patrón de cuadrícula en el control de ventana de cuadrícula. |
WM_LBUTTONDOWN | Determina si el cursor está dentro del control de ventana de cuadrícula cuando el usuario presiona el botón izquierdo del mouse. Si es así, el procedimiento del cuadro de diálogo invierte la celda de cuadrícula adecuada y registra el estado de esa celda en una matriz de bits que se usa para crear el mapa de bits para el pincel personalizado. |
WM_COMMAND | Procesa la entrada de los tres controles de botón de inserción. Si el usuario hace clic en el botón Probar patrón , el procedimiento del cuadro de diálogo pinta el control Patrón de prueba con el nuevo patrón de pincel personalizado. Si el usuario hace clic en el botón Aceptar o Cancelar , el procedimiento del cuadro de diálogo realiza acciones en consecuencia. |
Para obtener más información sobre los mensajes y el procesamiento de mensajes, vea Mensajes y colas de mensajes.
Después de escribir el procedimiento del cuadro de diálogo, incluya la definición de función para el procedimiento en el archivo de encabezado de la aplicación y, a continuación, llame al procedimiento del cuadro de diálogo en el punto adecuado de la aplicación.
El siguiente extracto del archivo de encabezado de la aplicación muestra la definición de función para el procedimiento del cuadro de diálogo y las dos funciones a las que llama.
BOOL CALLBACK BrushDlgProc(HWND, UINT, WPARAM, LPARAM);
int GetStrLngth(LPTSTR);
DWORD RetrieveWidth(LPTSTR, int);
Por último, el código siguiente muestra cómo se llama al procedimiento de cuadro de diálogo desde el archivo de código fuente de la aplicación.
DialogBox((HANDLE)GetModuleHandle(NULL),
(LPTSTR)"CustBrush",
hWnd,
(DLGPROC) BrushDlgProc);
Normalmente, esta llamada se realiza en respuesta al usuario que elige una opción en el menú de la aplicación.