第一个要介绍的是画笔。
通常我们理解的划线,应该是在划线函数中指明,我这条线画出来应该有多宽,线的类型是什么(比如虚线,点划线,实现)等等。而且很多地方就是这样做的,比如开源计算机视觉库OpenCV,Matlab等等中就是这样。但是Windows程序设计却是另一种思路:我先设计一个画笔,这根笔决定了我划线的颜色,粗细,线型等等。然后选择这根笔,最后划线。这样做好处其实也很多,大家如果习惯了word或者visio里面的绘图的话,也不难理解这样做的方便之处。
举一个例子:
#include <windows.h> #include <math.h> #define NUM 1000 #define TWOPI (2*3.14159) #define LOGWIDE 4000 #define LOGHIGH 3000 LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM); int WINAPI WinMain(HINSTANCE hInstance, //当前实例句柄 HINSTANCE hPrevInstance, //先前实例句柄 LPSTR lpCmdLine, //命令行 int iCmdShow) //显示状态 { static TCHAR szAppName[] = TEXT("画图"); //窗口句柄 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)) { return -1; } //创建窗口 hwnd = CreateWindow(szAppName, //窗口类的名称,必须是已经注册的 TEXT("我的画图"), //窗口标题 WS_OVERLAPPEDWINDOW, //窗口风格 CW_USEDEFAULT, //X坐标 CW_USEDEFAULT, //Y坐标 CW_USEDEFAULT, //宽度 CW_USEDEFAULT, //高度 NULL, //父窗口句柄 NULL, //菜单窗口句柄 hInstance, //高级版本的windos忽略 NULL); //显示窗口 //ShowWindow(hwnd,SW_SHOWNA); 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) { HDC hdc; HPEN hPen; PAINTSTRUCT ps; int i; static int cxClient,cyClient; POINT apt[NUM]; switch(message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdc = BeginPaint(hwnd,&ps); for(i = 0; i < 256;i++) { /* //创建画笔:参数为:画笔风格,画笔宽度,画笔颜色 hPen = CreatePen(PS_SOLID,i,RGB(i,0,0)); SelectObject(hdc,hPen); MoveToEx(hdc,300,200,NULL); LineTo(hdc,300,500); DeleteObject(hPen); Sleep(10); */ MoveToEx(hdc, 0,cyClient/2,NULL); LineTo (hdc,cxClient,cyClient/2); MoveToEx(hdc, 0,cyClient/2,NULL); //画正弦曲线 for(i = 0; i < NUM;i++) { hPen = CreatePen(PS_SOLID,(int)(i/10),RGB((int)(i/4),0,0)); SelectObject(hdc,hPen); apt[i].x = i * cxClient / NUM; apt[i].y = (int)(cyClient /2*(1-sin(TWOPI *i/NUM))); LineTo(hdc,apt[i].x,apt[i].y); DeleteObject(hPen); //Sleep(10); } } EndPaint(hwnd,&ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,message,wParam,lParam); }
还是画正弦曲线,但是每画一笔,我都要改变线的宽度和颜色,其中(i/10)和(i/4)仅仅是为了让宽度和颜色的变化不会太快。
然后要介绍的是关于写字方面的内容DrawText。
首先要明白,你在窗口上写字DrawText时,要注意3中颜色:第一是背景的颜色,这通过wndclass.hbrBackground = (HBRUSH) GetStockObject (GRAY_BRUSH);改变;第二是你写的那些字颜色,通过SetTextColor(hdc,RGB(255,0,0));改变;第三是你写的那些字的背景颜色,就是说你写的那些字,占用了一个个方格,这些格子的背景是什么颜色的,这通过SetBkColor(hdc,RGB(128,128,128));来改变。但在通常情况下,我们把字的背景设为透明SetBkMode(hdc,TRANSPARENT);,让它随着窗口颜色变化而变化。下面我们看看这个简单的程序:
#include <windows.h> #include <math.h> LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM); int WINAPI WinMain(HINSTANCE hInstance, //当前实例句柄 HINSTANCE hPrevInstance, //先前实例句柄 LPSTR lpCmdLine, //命令行 int iCmdShow) //显示状态 { static TCHAR szAppName[] = TEXT("画图"); //窗口句柄 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.hbrBackground = (HBRUSH) GetStockObject (GRAY_BRUSH); //菜单:暂时没有 wndclass.lpszMenuName = NULL; //窗口类名 wndclass.lpszClassName = szAppName; //注册窗口 if(!RegisterClass(&wndclass)) { return -1; } //创建窗口 hwnd = CreateWindow(szAppName, //窗口类的名称,必须是已经注册的 TEXT("我的画图"), //窗口标题 WS_OVERLAPPEDWINDOW, //窗口风格 CW_USEDEFAULT, //X坐标 CW_USEDEFAULT, //Y坐标 CW_USEDEFAULT, //宽度 CW_USEDEFAULT, //高度 NULL, //父窗口句柄 NULL, //菜单窗口句柄 hInstance, //高级版本的windos忽略 NULL); //显示窗口 //ShowWindow(hwnd,SW_SHOWNA); 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) { HDC hdc; HPEN hPen; PAINTSTRUCT ps; int i; static int cxClient,cyClient; RECT rect; switch(message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdc = BeginPaint(hwnd,&ps); //设置背景颜色 //SetBkColor(hdc,RGB(128,128,128)); //将背景模式:透明 SetBkMode(hdc,TRANSPARENT); //将背景模式:不透明 //SetBkMode(hdc,OPAQUE); //设置字的颜色 SetTextColor(hdc,RGB(255,0,0)); //获取客户区坐标 GetClientRect(hwnd,&rect); DrawText(hdc,TEXT("Hello, Windows7!"),-1,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd,&ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,message,wParam,lParam); }