本文将实现对基本图形的绘制:
windows程序画图,大体上有3种方法:
(1)你告诉系统点的坐标和颜色,系统通过SetPixel来画。类似的,通过GetPixel来获取某一点像素值。
(2)使用MoveToEx、LineTo来划线,MoveToEx设置起点坐标,LineTo设置终点坐标,或者使用Polyline函数,这个函数接受一个POINT类型的数组,通过数组里的点连线。
(3)windows提供了一些基本图形绘制的函数供我们直接调用,比如Rectangle绘制矩形,Ellipse绘制椭圆,RoundRect绘制圆角椭圆。
有几点需要特别注意:
(1)实际上画椭圆也是先画矩形,然后计算内接椭圆得出的。
(2)画矩形(椭圆)时都是指定左上角和右下角画图,这与我们平时使用的画图软件(画图、visio)里是同样的,可以想象,他们实现的画图的方法应该与这里相同。
(3)程序运行的结果,使得对角线被椭圆遮挡住了。如果改变顺序,最后画对角线,就没有遮挡发生。这说明,画出的图,是“实心的”,不能简单的理解为只有轮廓。
对以上基本功能实现的代码如下:
#include <windows.h> #include <math.h> #define NUM 1000 #define TWOPI (2*3.14159) 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; PAINTSTRUCT ps; int i, j; 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 < 500;i++) { for(j = 0; j < 26;j++) { SetPixel(hdc,200+i,200+j,RGB(i,j*10,0)); } } Sleep(5000); //划线 //用点划线 for(i = 0; i < 500;i++) { for (int j = 0; j < 500; j++) { if (j % 50 == 0) { SetPixel(hdc, i, j, RGB(0, 0, 0)); } } } Sleep(5000); //用函数划线 MoveToEx (hdc,0, cyClient/2,NULL); LineTo (hdc,cxClient, cyClient/2); for(int i = 0; i< NUM;i++) { //把x轴等分成1000份 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); } //Polyline绘制,速度快于在for循环内LineTo Polyline(hdc,apt,NUM); Sleep(5000); //绘制矩形 Rectangle(hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8); Sleep(5000); //绘制对角线 MoveToEx(hdc, 0, 0, NULL); LineTo(hdc, cxClient, cyClient); MoveToEx(hdc, 0, cyClient, NULL); LineTo(hdc, cxClient, 0); Sleep(5000); //绘制椭圆 Ellipse(hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8); Sleep(5000); //绘制圆角矩形 RoundRect(hdc, cxClient / 4, cyClient / 4, 3 * cxClient / 4, 3 * cyClient / 4, //最后两个参数是圆角矩形的圆角形成的椭圆的长和宽 cxClient / 4, cyClient / 4); Sleep(5000); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }