Windows 程序设计 第5章 绘图基础
DEVCAPS1.c 代码
#include <Windows.h>
#define NUMLINES ((int) (sizeof(devcaps) / sizeof(devcaps[0])))
struct
{
int iIndex;
TCHAR *szLabel;
TCHAR *szDesc;
}
devcaps[] =
{
HORZSIZE, TEXT("HORZSIZE"), TEXT("Width in millimeters:"),
VERTSIZE, TEXT("VERTSIZE"), TEXT("Height in milimeters:"),
HORZRES, TEXT("HORZRES"), TEXT("Width in pixels:"),
VERTRES, TEXT("VERTRES"), TEXT("Height in raster lines:"),
BITSPIXEL, TEXT("BITSPIXEL"), TEXT("Color bits per pixel:"),
PLANES, TEXT("PLANES"), TEXT("Number of color planes:"),
NUMBRUSHES, TEXT("NUMBRUSHES"), TEXT("Number of device brushes"),
NUMPENS, TEXT("NUMPENS"), TEXT("Number of device pens:"),
NUMMARKERS, TEXT("NUMMARKERS"), TEXT("Number of device markers:"),
NUMFONTS, TEXT("NUMFONTS"), TEXT("Number of device fonts:"),
NUMCOLORS, TEXT("NUMCOLORS"), TEXT("Number of device colors:"),
PDEVICESIZE, TEXT("PDEVICESIZE"), TEXT("Size of device structure:"),
ASPECTX, TEXT("ASPECTX"), TEXT("Relative width of pixel:"),
ASPECTY, TEXT("ASPECTY"), TEXT("Relative height of pixel:"),
ASPECTXY, TEXT("ASPECTXY"), TEXT("Relative diagonal of pixel:"),
LOGPIXELSX, TEXT("LOGPIXELSX"), TEXT("Horizontal dots per inch:"),
LOGPIXELSY, TEXT("LOGPIXELSY"), TEXT("Vertical dots per inch:"),
SIZEPALETTE, TEXT("SIZEPALETTE"), TEXT("Number of palette entries:"),
NUMRESERVED, TEXT("NUMRESERVED"), TEXT("Reserved palette entries:"),
COLORRES, TEXT("COLORRES"), TEXT("Actual color resolution:")
};
LRESULT CALLBACK WndPorc(HWND, UINT, WPARAM, LPARAM);//设置回调函数 WndProc函数的返回值类型为LRESULT。该类型等价于LONG.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, PSTR szCmdLine, int iCmdShow)
{
static WCHAR szAppName[] = TEXT("Devcaps1"); //定义app名称
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW ; //指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
wndclass.lpfnWndProc = WndPorc; //指定窗口过程(必须是回调函数) *
//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
//一些额外的空间:
wndclass.cbClsExtra = 0; //预留的额外空间,一般为 0
wndclass.cbWndExtra = 0; //预留的额外空间,一般为 0
//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
wndclass.hInstance = hInstance; //应用程序的实例句柄
//下面的语句为所有基于该窗口类的窗口设定一个图标:
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //为所有基于该窗口类的窗口设定一个图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //为所有基于该窗口类的窗口设定一个鼠标指针
/*
下一个字段为这类窗口的客户区指定了背景色。
字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
画刷是一个图形学术语,表示用于区域填充的像素着色模式。
Windows有几个标准的画刷,又称“库存”画刷。
下面对GetStockObject的调用返回一个白色画刷的句柄:
*/
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //指定窗口背景色
//接下来的一个字段指定了窗口类的菜单。
//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
wndclass.lpszMenuName = NULL; //指定窗口菜单
//最后,必须为窗口类赋予一个名称。对一个小程序来说,
//这个名称可以简单地用程序名表示,
//如保存在变量szAppName中的字符串“HelloWin”:
wndclass.lpszClassName = szAppName; //指定窗口类名 *
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, //窗口类名
TEXT("画直线"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口样式
CW_USEDEFAULT, //初始x位置
CW_USEDEFAULT, //初始y位置
CW_USEDEFAULT, //初始x尺寸
CW_USEDEFAULT, //初始y尺寸
NULL, //父窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL //创建参数
);
ShowWindow(hwnd, iCmdShow); //显示窗口 函 数用于设置窗口的显示状态。
UpdateWindow(hwnd); //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程
while (GetMessage(&msg, NULL, 0, 0)) //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
{
TranslateMessage(&msg); //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
DispatchMessage(&msg); //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
}
return msg.wParam;
}
LRESULT CALLBACK WndPorc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
static int cxChar, cyChar, cxCaps;
TCHAR szBuffer[10];
int i;
HDC hdc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
//RECT rect;
switch (message)
{
case WM_CREATE: // 当要获取系统的字体时
hdc = GetDC(hwnd);
GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth;
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2)*cxChar / 2;
cyChar = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hwnd, hdc);
return 0;
case WM_PAINT: //绘制窗口
hdc = BeginPaint(hwnd, &ps); //Device Context设备上下文
for (i = 0; i != NUMLINES; ++i)
{
TextOut(hdc, 0, cyChar * i, devcaps[i].szLabel,lstrlen(devcaps[i].szLabel));
TextOut(hdc, 14 * cxCaps, cyChar * i, devcaps[i].szDesc, lstrlen(devcaps[i].szDesc));
SetTextAlign(hdc, TA_RIGHT | TA_TOP);
TextOut(hdc, 14 * cxCaps + 35 * cxChar, cyChar * i, szBuffer, wsprintf(szBuffer, TEXT("%5d"), GetDeviceCaps(hdc, devcaps[i].iIndex)));
SetTextAlign(hdc, TA_LEFT | TA_TOP);
}
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY: //处理窗口关闭的消息
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
显示结果
SINEWAVE.c 代码 点和线的绘制
#include <Windows.h>
#include <math.h>
#define NUM 1000
#define TWOPI (2*3.14159)
LRESULT CALLBACK WndPorc(HWND, UINT, WPARAM, LPARAM);//设置回调函数 WndProc函数的返回值类型为LRESULT。该类型等价于LONG.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, PSTR szCmdLine, int iCmdShow)
{
static WCHAR szAppName[] = TEXT("SineWave"); //定义app名称
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW; //指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
wndclass.lpfnWndProc = WndPorc; //指定窗口过程(必须是回调函数) *
//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
//一些额外的空间:
wndclass.cbClsExtra = 0; //预留的额外空间,一般为 0
wndclass.cbWndExtra = 0; //预留的额外空间,一般为 0
//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
wndclass.hInstance = hInstance; //应用程序的实例句柄
//下面的语句为所有基于该窗口类的窗口设定一个图标:
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //为所有基于该窗口类的窗口设定一个图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //为所有基于该窗口类的窗口设定一个鼠标指针
/*
下一个字段为这类窗口的客户区指定了背景色。
字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
画刷是一个图形学术语,表示用于区域填充的像素着色模式。
Windows有几个标准的画刷,又称“库存”画刷。
下面对GetStockObject的调用返回一个白色画刷的句柄:
*/
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //指定窗口背景色
//接下来的一个字段指定了窗口类的菜单。
//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
wndclass.lpszMenuName = NULL; //指定窗口菜单
//最后,必须为窗口类赋予一个名称。对一个小程序来说,
//这个名称可以简单地用程序名表示,
//如保存在变量szAppName中的字符串“HelloWin”:
wndclass.lpszClassName = szAppName; //指定窗口类名 *
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, //窗口类名
TEXT("Sine Wave Using PolyLine!"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口样式
CW_USEDEFAULT, //初始x位置
CW_USEDEFAULT, //初始y位置
CW_USEDEFAULT, //初始x尺寸
CW_USEDEFAULT, //初始y尺寸
NULL, //父窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL //创建参数
);
ShowWindow(hwnd, iCmdShow); //显示窗口 函 数用于设置窗口的显示状态。
UpdateWindow(hwnd); //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程
while (GetMessage(&msg, NULL, 0, 0)) //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
{
TranslateMessage(&msg); //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
DispatchMessage(&msg); //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
}
return msg.wParam;
}
LRESULT CALLBACK WndPorc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
static int cxClient, cyClient;
int i;
HDC hdc;
PAINTSTRUCT ps;
POINT apt[NUM];
//TEXTMETRIC tm;
//RECT rect;
switch (message)
{
case WM_SIZE:
cxClient = LOWORD(lparam);
cyClient = HIWORD(lparam);
return 0;
case WM_PAINT: //绘制窗口
hdc = BeginPaint(hwnd, &ps); //Device Context设备上下文
//画矩形
Rectangle(hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8); //Rectangle(hdc,xLeft,yTop,xRight,yBottom)
//画对角线
MoveToEx(hdc, 0, 0, NULL);
LineTo(hdc, cxClient, cyClient);
MoveToEx(hdc, 0, cyClient, NULL);
LineTo(hdc, cxClient, 0);
//画椭圆
Ellipse(hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8); //Ellipse(hdc,xLeft,yTop,xRight,yBottom)
//画圆角矩形
RoundRect(hdc, cxClient / 4, cyClient / 4, 3 * cxClient / 4, 3 * cyClient / 4, cxClient / 4, cyClient / 4);//RoundRect(hdc, ,xLeft,yTop,xRight,yBottom, xCornerEllipse, yCornerEllipse);
//画曲线
//for ( i = 0; i < NUM; i++)
// {
// apt[i].x = i*cxClient / NUM;
// apt[i].y = (int)(cyClient / 2 * (1 - sin(TWOPI*i / NUM)));
//}
//Polyline(hdc,apt,NUM);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY: //处理窗口关闭的消息
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
显示结果:
LINEDEMO.c 代码 贝塞尔样条曲线
#include <Windows.h>
#include <math.h>
LRESULT CALLBACK WndPorc(HWND, UINT, WPARAM, LPARAM);//设置回调函数 WndProc函数的返回值类型为LRESULT。该类型等价于LONG.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, PSTR szCmdLine, int iCmdShow)
{
static WCHAR szAppName[] = TEXT("SineWave"); //定义app名称
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW; //指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
wndclass.lpfnWndProc = WndPorc; //指定窗口过程(必须是回调函数) *
//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
//一些额外的空间:
wndclass.cbClsExtra = 0; //预留的额外空间,一般为 0
wndclass.cbWndExtra = 0; //预留的额外空间,一般为 0
//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
wndclass.hInstance = hInstance; //应用程序的实例句柄
//下面的语句为所有基于该窗口类的窗口设定一个图标:
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //为所有基于该窗口类的窗口设定一个图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //为所有基于该窗口类的窗口设定一个鼠标指针
/*
下一个字段为这类窗口的客户区指定了背景色。
字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
画刷是一个图形学术语,表示用于区域填充的像素着色模式。
Windows有几个标准的画刷,又称“库存”画刷。
下面对GetStockObject的调用返回一个白色画刷的句柄:
*/
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //指定窗口背景色
//接下来的一个字段指定了窗口类的菜单。
//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
wndclass.lpszMenuName = NULL; //指定窗口菜单
//最后,必须为窗口类赋予一个名称。对一个小程序来说,
//这个名称可以简单地用程序名表示,
//如保存在变量szAppName中的字符串“HelloWin”:
wndclass.lpszClassName = szAppName; //指定窗口类名 *
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, //窗口类名
TEXT("Sine Wave Using PolyLine!"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口样式
CW_USEDEFAULT, //初始x位置
CW_USEDEFAULT, //初始y位置
CW_USEDEFAULT, //初始x尺寸
CW_USEDEFAULT, //初始y尺寸
NULL, //父窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL //创建参数
);
ShowWindow(hwnd, iCmdShow); //显示窗口 函 数用于设置窗口的显示状态。
UpdateWindow(hwnd); //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程
while (GetMessage(&msg, NULL, 0, 0)) //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
{
TranslateMessage(&msg); //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
DispatchMessage(&msg); //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
}
return msg.wParam;
}
void DrawBezier(HDC hdc, POINT apt[])
{
PolyBezier(hdc, apt, 4);
MoveToEx(hdc, apt[0].x, apt[0].y, NULL);
LineTo(hdc, apt[1].x, apt[1].y);
MoveToEx(hdc, apt[2].x, apt[2].y, NULL);
LineTo(hdc, apt[3].x, apt[3].y);
}
LRESULT CALLBACK WndPorc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
static int cxClient, cyClient;
int i;
HDC hdc;
PAINTSTRUCT ps;
static POINT apt[4];
//TEXTMETRIC tm;
//RECT rect;
switch (message)
{
case WM_SIZE:
cxClient = LOWORD(lparam);
cyClient = HIWORD(lparam);
apt[0].x = cxClient / 4;
apt[0].y = cyClient / 2;
apt[1].x = cxClient / 2;
apt[1].y = cyClient / 4;
apt[2].x = cxClient / 2;
apt[2].y = 3 * cyClient / 4;
apt[3].x = 3 * cxClient / 4;
apt[3].y = cyClient / 2;
return 0;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MOUSEMOVE:
if (wparam & MK_LBUTTON || wparam & MK_RBUTTON)
{
hdc = GetDC(hwnd);
SelectObject(hdc, GetStockObject(WHITE_PEN));
DrawBezier(hdc, apt);
if (wparam & MK_LBUTTON)
{
apt[1].x = LOWORD(lparam);
apt[1].y = HIWORD(lparam);
}
if (wparam & MK_RBUTTON)
{
apt[2].x = LOWORD(lparam);
apt[2].y = HIWORD(lparam);
}
SelectObject(hdc, GetStockObject(BLACK_PEN));
DrawBezier(hdc, apt);
ReleaseDC(hwnd, hdc);
}
case WM_PAINT: //绘制窗口
hdc = BeginPaint(hwnd, &ps); //Device Context设备上下文
DrawBezier(hdc, apt);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY: //处理窗口关闭的消息
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
结果显示:
ALTWIND.c 绘制填充区域
#include <Windows.h>
#include <math.h>
LRESULT CALLBACK WndPorc(HWND, UINT, WPARAM, LPARAM);//设置回调函数 WndProc函数的返回值类型为LRESULT。该类型等价于LONG.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, PSTR szCmdLine, int iCmdShow)
{
static WCHAR szAppName[] = TEXT("SineWave"); //定义app名称
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW; //指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
wndclass.lpfnWndProc = WndPorc; //指定窗口过程(必须是回调函数) *
//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
//一些额外的空间:
wndclass.cbClsExtra = 0; //预留的额外空间,一般为 0
wndclass.cbWndExtra = 0; //预留的额外空间,一般为 0
//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
wndclass.hInstance = hInstance; //应用程序的实例句柄
//下面的语句为所有基于该窗口类的窗口设定一个图标:
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //为所有基于该窗口类的窗口设定一个图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //为所有基于该窗口类的窗口设定一个鼠标指针
/*
下一个字段为这类窗口的客户区指定了背景色。
字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
画刷是一个图形学术语,表示用于区域填充的像素着色模式。
Windows有几个标准的画刷,又称“库存”画刷。
下面对GetStockObject的调用返回一个白色画刷的句柄:
*/
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //指定窗口背景色
//接下来的一个字段指定了窗口类的菜单。
//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
wndclass.lpszMenuName = NULL; //指定窗口菜单
//最后,必须为窗口类赋予一个名称。对一个小程序来说,
//这个名称可以简单地用程序名表示,
//如保存在变量szAppName中的字符串“HelloWin”:
wndclass.lpszClassName = szAppName; //指定窗口类名 *
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, //窗口类名
TEXT("Sine Wave Using PolyLine!"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口样式
CW_USEDEFAULT, //初始x位置
CW_USEDEFAULT, //初始y位置
CW_USEDEFAULT, //初始x尺寸
CW_USEDEFAULT, //初始y尺寸
NULL, //父窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL //创建参数
);
ShowWindow(hwnd, iCmdShow); //显示窗口 函 数用于设置窗口的显示状态。
UpdateWindow(hwnd); //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程
while (GetMessage(&msg, NULL, 0, 0)) //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
{
TranslateMessage(&msg); //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
DispatchMessage(&msg); //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
}
return msg.wParam;
}
LRESULT CALLBACK WndPorc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
static POINT aptFigure[10] = {10,70,50,70,50,10,90,10,90,50,30,50,30,90,70,90,70,30,10,30};
static int cxClient, cyClient;
int i;
HDC hdc;
PAINTSTRUCT ps;
POINT apt[10];
//TEXTMETRIC tm;
//RECT rect;
switch (message)
{
case WM_SIZE:
cxClient = LOWORD(lparam);//客户区的长度
cyClient = HIWORD(lparam);//客户区的高度
return 0;
case WM_PAINT: //绘制窗口
hdc = BeginPaint(hwnd, &ps); //Device Context设备上下文
//SelectObject
//把一个对象(位图、画笔、画刷等)选入指定的设备描述表。新的对象代替同一类型的老对象
SelectObject(hdc,GetStockObject(GRAY_BRUSH));//GetStockObject()该函数检索预定义的备用笔、刷子、字体或者调色板的句柄
for (i = 0; i < 10; i++)
{
apt[i].x = cxClient * aptFigure[i].x / 200;
apt[i].y = cyClient * aptFigure[i].y / 100;
}
//参数iMode:其有两种填充模式:ALTERNATE和WINDING;在默认情况下为ALTERNATE;
//模式ALTERNATE:其从封闭区域中的一个点向无穷远处水平画一条射线,只有当该射线穿越奇数条边框线时,封闭区域才被填充,如为偶数,则不填充该区域;
//模式WINDING:方法一样,如为奇数,填充该区域;如为偶数则要根据边框线的方向来判断:如果穿过的边框线在不同方向的边框线数目相等,则不填充,如不等,则填充。
SetPolyFillMode(hdc,ALTERNATE);
Polygon(hdc,apt,10);//该函数画一个由直线相闻的两个以上顶点组成的多边形,用当前画笔画多边形轮廓,用当前画刷和多边形填充模式填充多边形
for (i = 0; i < 10; i++)
{
apt[i].x += cxClient / 2;
}
SetPolyFillMode(hdc, WINDING);
Polygon(hdc, apt, 10);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY: //处理窗口关闭的消息
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
显示结果
WHATSIZE.c 代码
#include <Windows.h>
#include <math.h>
LRESULT CALLBACK WndPorc(HWND, UINT, WPARAM, LPARAM);//设置回调函数 WndProc函数的返回值类型为LRESULT。该类型等价于LONG.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, PSTR szCmdLine, int iCmdShow)
{
static WCHAR szAppName[] = TEXT("What Size"); //定义app名称
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW; //指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
wndclass.lpfnWndProc = WndPorc; //指定窗口过程(必须是回调函数) *
//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
//一些额外的空间:
wndclass.cbClsExtra = 0; //预留的额外空间,一般为 0
wndclass.cbWndExtra = 0; //预留的额外空间,一般为 0
//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
wndclass.hInstance = hInstance; //应用程序的实例句柄
//下面的语句为所有基于该窗口类的窗口设定一个图标:
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //为所有基于该窗口类的窗口设定一个图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //为所有基于该窗口类的窗口设定一个鼠标指针
/*
下一个字段为这类窗口的客户区指定了背景色。
字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
画刷是一个图形学术语,表示用于区域填充的像素着色模式。
Windows有几个标准的画刷,又称“库存”画刷。
下面对GetStockObject的调用返回一个白色画刷的句柄:
*/
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //指定窗口背景色
//接下来的一个字段指定了窗口类的菜单。
//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
wndclass.lpszMenuName = NULL; //指定窗口菜单
//最后,必须为窗口类赋予一个名称。对一个小程序来说,
//这个名称可以简单地用程序名表示,
//如保存在变量szAppName中的字符串“HelloWin”:
wndclass.lpszClassName = szAppName; //指定窗口类名 *
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, //窗口类名
TEXT("Sine Wave Using PolyLine!"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口样式
CW_USEDEFAULT, //初始x位置
CW_USEDEFAULT, //初始y位置
CW_USEDEFAULT, //初始x尺寸
CW_USEDEFAULT, //初始y尺寸
NULL, //父窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL //创建参数
);
ShowWindow(hwnd, iCmdShow); //显示窗口 函 数用于设置窗口的显示状态。
UpdateWindow(hwnd); //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程
while (GetMessage(&msg, NULL, 0, 0)) //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
{
TranslateMessage(&msg); //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
DispatchMessage(&msg); //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
}
return msg.wParam;
}
void Show(HWND hwnd,HDC hdc,int xText,int yText,int iMapMode,TCHAR * szMaoMode)
{
TCHAR szBuffer[60];
RECT rect;
SaveDC(hdc);
SetMapMode(hdc,iMapMode);
GetClientRect(hwnd,&rect);
DPtoLP(hdc,(PPOINT)&rect,2);
RestoreDC(hdc,-1);
TextOut(hdc,xText,yText,szBuffer,wsprintf(szBuffer,TEXT("%-20s %7d %7d %7d %7d"),szMaoMode,rect.left,rect.right,rect.top,rect.bottom));
}
LRESULT CALLBACK WndPorc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
//static POINT aptFigure[10] = { 10,70,50,70,50,10,90,10,90,50,30,50,30,90,70,90,70,30,10,30 };
static int cxChar, cyChar;
static TCHAR szHeading[] =
TEXT("Mapping Mode Left Right Top Bottom");
static TCHAR szUndLine[] =
TEXT("------------------------------------------------------------");
int i;
HDC hdc;
PAINTSTRUCT ps;
POINT apt[10];
TEXTMETRIC tm;
//RECT rect;
switch (message)
{
case WM_CREATE:
hdc = GetDC(hwnd);
SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
GetTextMetrics(hdc,&tm);
cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hwnd,hdc);
return 0;
case WM_PAINT: //绘制窗口
hdc = BeginPaint(hwnd, &ps); //Device Context设备上下文
SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, 1, 1, NULL);
SetViewportExtEx(hdc, cxChar, cyChar, NULL);
TextOut(hdc, 1, 1, szHeading, lstrlen(szHeading));
TextOut(hdc, 1, 2, szUndLine, lstrlen(szUndLine));
Show(hwnd, hdc, 1, 3, MM_TEXT, TEXT("TEXT (pixels)"));
Show(hwnd, hdc, 1, 4, MM_LOMETRIC, TEXT("LOMETRIC (.1 mm)"));
Show(hwnd, hdc, 1, 5, MM_HIMETRIC, TEXT("HIMETRIC (.01 mm)"));
Show(hwnd, hdc, 1, 6, MM_LOENGLISH, TEXT("LOENGLISH (.01 in)"));
Show(hwnd, hdc, 1, 7, MM_HIENGLISH, TEXT("HIENGLISH (.001 in)"));
Show(hwnd, hdc, 1, 8, MM_TWIPS, TEXT("TWIPS (1/1440 in)"));
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY: //处理窗口关闭的消息
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
显示结果
RANDRECT.c 代码 随机矩形
#include <windows.h>
#include <stdlib.h> // for the rand function
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawRectangle(HWND);
int cxClient, cyClient;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("RandRect");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, TEXT("Random Rectangles"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (true)
{
//PeekMessage有消息时返回true,无消息时返回false,最后一个参数若为PM_REMOVE,表示消息从队列中取出来处理后删除,如果想处理后不删除,则置为 PM_NOREMOVE,不管队列中有没消息,该函数立即返回
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
DrawRectangle(hwnd); //每一次循环都重新绘出这个随机矩形
}
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch (iMsg)
{
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
void DrawRectangle(HWND hwnd)
{
HBRUSH hBrush;
HDC hdc;
RECT rect;
if (cxClient == 0 || cyClient == 0)
return;
SetRect(&rect, rand() % cxClient, rand() % cyClient, rand() % cxClient, rand() % cyClient);//设置矩形
hBrush = CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256));//创建画刷
hdc = GetDC(hwnd);
FillRect(hdc, &rect, hBrush);//填充矩形,不需要把设备描述表句柄装入设备描述表中,因为可以直接使用画刷hBrush
ReleaseDC(hwnd, hdc);
DeleteObject(hBrush);//删除画刷
}
显示结果
CLOVER.c 代码
#include <windows.h>
#include <math.h>
#define TWO_PI (2.0 * 3.14159)
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawRectangle(HWND);
int cxClient, cyClient;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("clover");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, TEXT("Draw a Clover"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HRGN hRgnClip;
static int cxClient, cyClient;
double fAngle, fRadius;
HCURSOR hCursor;
HDC hdc;
HRGN hRgnTemp[6];
int i;
PAINTSTRUCT ps;
switch (message)
{
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
ShowCursor(TRUE);
if (hRgnClip)
DeleteObject(hRgnClip);
//CreateEllipticRgn创建一个椭圆,该椭圆与X1,Y1和X2,Y2坐标点确定的矩形内切
hRgnTemp[0] = CreateEllipticRgn(0, cyClient / 3, cxClient / 2, 2 * cyClient / 3);
hRgnTemp[1] = CreateEllipticRgn(cxClient / 2, cyClient / 3, cxClient, 2 * cyClient / 3);
hRgnTemp[2] = CreateEllipticRgn(cxClient / 3, 0, 2 * cxClient / 3, cyClient / 2);
hRgnTemp[3] = CreateEllipticRgn(cxClient / 3, cyClient / 2, 2 * cxClient / 3, cyClient);
hRgnTemp[4] = CreateRectRgn(0, 0, 1, 1);
hRgnTemp[5] = CreateRectRgn(0, 0, 1, 1);
hRgnClip = CreateRectRgn(0, 0, 1, 1);
//CLOVER 先创建 4 个椭圆区域,它们被存储在 hRgnTemp 数组的前 4 个元素中。接着程序创建三个“ 空 ” 区域:
//在客户区左边和右边的两个椭圆区域先合并:
CombineRgn(hRgnTemp[4], hRgnTemp[0], hRgnTemp[1], RGN_OR);
//同样地,在客户区顶部和底部的两个椭圆区域也合并了:
CombineRgn(hRgnTemp[5], hRgnTemp[2], hRgnTemp[3], RGN_OR);
//最后两个合并后的区域再合并成 hRgnClip :
CombineRgn(hRgnClip, hRgnTemp[4], hRgnTemp[5], RGN_XOR);
//RGN_XOR 标识符表示要从结果区域中排除重叠的区域。最后,6 个临时区域被删除:
for (i = 0; i < 6; i++)
DeleteObject(hRgnTemp[i]);
SetCursor(hCursor);
ShowCursor(FALSE);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
//相对结果而言,WM_PAINT 消息的处理很简单。视口原点设置在客户区的中心(这样使画直线更容易),在处理 WM_SIZE 消息时创建的区域被选入设备环境作为剪裁区域:
SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);
SelectClipRgn(hdc, hRgnClip);
// hypot 计算直角三角形斜边的长
//现在,剩下要做的就是画直线了,一共画 360 条,每一度画一条。每条线的长度是变量 fRadius ,它表示的是从中心到客户区角落的距离:
fRadius = _hypot(cxClient / 2.0, cyClient / 2.0);
for (fAngle = 0.0; fAngle < TWO_PI; fAngle += TWO_PI / 360)
{
MoveToEx(hdc, 0, 0, NULL);
LineTo(hdc, int(fRadius * cos(fAngle) + 0.5), int(-fRadius * sin(fAngle) + 0.5));
}
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
//在处理 WM_DESTROY 消息期间,剪裁区域被删除:
DeleteObject(hRgnClip);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
显示结果