您可以使用画笔通过使用GDI功能来绘制几乎任何形状的内部。这包括矩形,椭圆,多边形和路径的内部。根据应用程序的要求,您可以使用指定颜色的实心笔刷,库存刷子,填充刷或图案刷。
本节包含演示创建自定义画刷对话框的代码示例。对话框包含一个表示Windows用作画笔的位图的网格。用户可以使用此网格创建模式刷位图,然后单击测试模式按钮查看自定义模式。
下图显示了使用“自定义画笔”对话框创建的图案。
要显示对话框,必须先创建一个对话框模板。以下对话框模板定义“自定义画笔”对话框。
CustBrush对话6,18,160,118
STYLE WS_DLGFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION“自定义画笔”
FONT 8,“MS Sans Serif”
BEGIN
控制“”,IDD_GRID,“静态”,SS_BLACKFRAME |
WS_CHILD, 3, 2, 83, 79
控制“”,IDD_RECT,“静态”,SS_BLACKFRAME |
WS_CHILD, 96, 11, 57, 28
PUSHBUTTON“测试模式”,IDD_PAINTRECT,96,47,57,14
PUSHBUTTON "OK", IDD_OK, 29, 98, 40, 14
PUSHBUTTON“取消”,IDD_CANCEL,92,98,40,14en
END
自定义画笔对话框包含五个控件:位图网格窗口,模式查看窗口和三个按钮,标记为测试模式,确定和取消。测试图案按钮使用户可以查看图案。对话框模板指定对话框窗口的总体尺寸,为每个控件分配一个值,指定每个控件的位置等等。(有关创建对话框模板的更多信息,请参阅对话框.)
对话框模板中的控件值是在应用程序头文件中定义如下的常量。
#定义IDD_GRID 120
#定义IDD_RECT 121
的#define IDD_PAINTRECT 122
的#define IDD_OK 123
#定义IDD_CANCEL 124
创建对话框模板并将其包含在应用程序的资源定义文件中后,您必须编写一个对话框过程。此过程处理Windows发送到对话框的消息。应用程序源代码的以下摘录显示了自定义画笔对话框和调用的两个应用程序定义函数的对话框过程。
int APIENTRY BrushDlgProc(HWND hdlg,WORD消息,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; /* DC handle */
int x, y, deltaX, deltaY; /* drawing coordinates */
POINTS ptlHit; /* mouse coordinates */
int i; /* count variable */
开关(讯息)
{
case WM_INITDIALOG:
/*
*检索网格窗口的窗口句柄
*图案刷控件
*/
hwndGrid = GetDlgItem(hdlg, IDD_GRID);
hwndBrush = GetDlgItem(hdlg, IDD_RECT);
/ *初始化定义的数组数组
*定制刷模式,值为1,产生一个
*固体白色刷子)。
*/
for (i=0; i<8; i++)
bBrushBits[i] = 0xFF;
/*
*检索网格窗口和图案画笔的尺寸
*控件。
*/
GetClientRect(hwndGrid, &rctGrid);
GetClientRect(hwndBrush, &rctBrush);
/ *确定单个单元格的宽度和高度。*/
deltaX = (rctGrid.right - rctGrid.left)/8;
deltaY = (rctGrid.bottom - rctGrid.top)/8;
/ *初始化单元格矩形的数组。*/
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:
/ *绘制网格。*/
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:
/ *将鼠标坐标存储在POINT结构中。*/
ptlHit = MAKEPOINTS((POINTS FAR *)lParam);
/*
*创建一个带有尺寸的矩形区域
*与网格对应的坐标
*窗口。
*/
hrgnCell = CreateRectRgn(rctGrid.left, rctGrid.top,
rctGrid.right, rctGrid.bottom);
/ *检索网格窗口的窗口DC。*/
hdc = GetDC(hwndGrid);
/ *选择DC中的区域。*/
SelectObject(hdc, hrgnCell);
/ *测试一个按钮点击网格窗口矩形。*/
if(PtInRegion(hrgnCell,ptlHit.x,ptlHit.y)){
/*
* A button click occurred in the grid-window rectangle;
*隔离它发生的单元格。
*/
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);
/ *设置适当的刷位。*/
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;
/ *置位后退出“for”循环。*/
break;
} /* 万一 */
/* Release the DC for the control.
} /* 万一 */
/ *释放控制器的DC。*/
ReleaseDC(hwndGrid, hdc);
return TRUE;
case WM_COMMAND:
开关(wParam){
case IDD_PAINTRECT:
hdc = GetDC(hwndBrush);
/ *创建单色位图。*/
hbm = CreateBitmap(8, 8, 1, 1,
(LPBYTE)bBrushBits);
/ *在DC中选择自定义画笔。*/
hbrush = CreatePatternBrush(hbm);
hbrushOld = SelectObject(hdc, hbrush);
/ *使用自定义画笔填充矩形。*/
Rectangle(hdc,rctBrush.left,rctBrush.top,
rctBrush.right, rctBrush.bottom);
/ *清理内存。*/
SelectObject(hdc, hbrushOld);
DeleteObject(hbrush);
DeleteObject(hbm);
ReleaseDC(hwndBrush, hdc);
return TRUE;
case IDD_OK:
case IDD_CANCEL:
EndDialog(hdlg, TRUE);
return TRUE;
Draws the grid pattern in the grid-window control.
break;
默认:
return FALSE;
}
}
砖Getstrlngth(LPTSTR开瑞)
{
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;
}
“自定义笔刷”对话框的对话框过程将处理四个消息,如下表所述。
信息 | 行动 |
WM_INITDIALOG | 检索网格窗口和图案刷控件的窗口句柄和尺寸,计算网格窗口控件中单个单元格的尺寸,并初始化网格单元坐标数组。 |
WM_PAINT | 在网格窗口控件中绘制网格图案。 |
WM_LBUTTONDOWN | 确定当用户按下鼠标左键时,光标是否在网格窗口控件内。如果是这样,对话框过程会反转适当的网格单元格,并将该单元格的状态记录在用于创建自定义画笔位图的位数组中。 |
WM_COMMAND | 处理三个按钮控件的输入。如果用户按下测试图案按钮,对话框过程将使用新的自定义画笔模式绘制测试图案控件。如果用户按确定或取消按钮,对话框过程将相应地执行操作。 |
有关消息和消息处理的更多信息,请参阅消息和消息队列.
在编写对话框过程之后,将其导出到模块定义文件中,包括应用程序头文件中过程的功能定义,然后在应用程序的适当位置调用对话框过程。
模块定义文件的以下摘录显示如何导出自定义画笔的对话框过程。
; Export all functions that are called by a Windows routine.
EXPORTS
MainWndProc @1 ; name of window processing function
BrushDlgProc @2 ; name of custom-brush processing function
应用程序头文件的以下摘录显示了对话框过程的功能定义及其调用的两个函数。
int APIENTRY BrushDlgProc(HWND hdlg,WORD消息,LONG wParam,
LONG lParam);
int GetStrLngth(LPTSTR cArray);
DWORD RetrieveWidth(LPTSTR cArray, int iLength);
最后,以下代码显示了如何从应用程序的源代码文件中调用对话框过程。在此示例中,当用户从应用程序的菜单中选择一个选项时,将调用对话框过程。
开关(讯息)
{
case WM_CREATE:
break;
case WM_COMMAND: //命令从应用程序菜单
开关(wParam中)
{
case IDM_CUSTOMBRUSH:
DialogBox((HANDLE)GetModuleHandle(NULL),
(LPTSTR)“CustBrush”,hWnd,
(DLGPROC)BrushDlgProc);
break;