Windows绘图
1 图形绘制
1.1 图形绘制的方式
获取到绘图句柄-设备描述表(DC),使用相应的绘图的API,在设备上绘制图形.
1.2 颜色
R\G\B三色, 每种颜色8位, 共24位颜色.
32位颜色: 颜色数量24位颜色, 多出来的8位表示灰度.
16位: 颜色数量2的16次方.
Win32下,颜色的定义 COLORREF(DWORD), RGB宏定义颜色
COLORREF nColor = RGB( 0, 0, 0 );
COLORREF nColor = RGB( 255,255,255 );
COLORREF nColor = RGB( 255,0, 0 );
从一个颜色中获取RGB三色:
int nBlue = GetBValue( nColor );
int nRed = GetRValue( nColor );
int nGreen= GetGValue( nColor );
下面是具体的代码
// winDraw.cpp.cpp : 定义应用程序的入口点。 // #include "stdafx.h" #include "winDraw.cpp.h" #include <stdio.h> #define MAX_LOADSTRING 100 // 全局变量: HINSTANCE hInst; // 当前实例 TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本 TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名 int g_nDrawType = 0; //绘图命令 COLORREF g_nPenColor = RGB( 0, 0, 0 ); //默认画笔颜色 int g_nPenStyle = PS_SOLID; //默认画笔类型 int g_nPenWdith = 1; //默认画笔宽度 COLORREF g_nBrushColor = RGB( 255, 255, 255 ); //默认画笔颜色 // 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: 在此放置代码。 MSG msg; HACCEL hAccelTable; // 初始化全局字符串 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_WINDRAWCPP, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDRAWCPP)); // 主消息循环: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; } // // 函数: MyRegisterClass() // // 目的: 注册窗口类。 // // 注释: // // 仅当希望 // 此代码与添加到 Windows 95 中的“RegisterClassEx” // 函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要, // 这样应用程序就可以获得关联的 // “格式正确的”小图标。 // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDRAWCPP)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /*加载菜单项 也可以在创建windows的时候加载菜单*/ wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WINDRAWCPP); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } // // 函数: InitInstance(HINSTANCE, int) // // 目的: 保存实例句柄并创建主窗口 // // 注释: // // 在此函数中,我们在全局变量中保存实例句柄并 // 创建和显示主程序窗口。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // 将实例句柄存储在全局变量中 hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } void OnCommand(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; //命令ID wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 分析菜单选择: switch (wmId){ case ID_32774://绘制点 case ID_32775: case ID_32772: case ID_32776://绘制圆弧 case ID_32777://绘制折线 case ID_32780://绘制曲线 case ID_32781://绘制多样式曲线 case ID_32782://绘制矩形 case ID_32783://绘制圆 case ID_32785://绘制饼 case ID_32786://绘制炫 case ID_32787://绘制多边形 //保存图形绘制类型 g_nDrawType = wmId; InvalidateRect(hWnd,NULL,TRUE);//刷新窗口,会触发WM_PAINT break; case ID_32790://绘制画笔红色 //保存图形绘制类型 g_nPenColor = RGB(255,0,0); InvalidateRect(hWnd,NULL,TRUE);//刷新窗口,会触发WM_PAINT break; case ID_32792://画笔样式 g_nPenStyle = PS_SOLID; InvalidateRect(hWnd,NULL,TRUE);//刷新窗口,会触发WM_PAINT break; case ID_32794://画笔样式 g_nPenStyle = PS_DASH; InvalidateRect(hWnd,NULL,TRUE);//刷新窗口,会触发WM_PAINT break; case ID_32796://画笔样式 g_nPenWdith = 1; InvalidateRect(hWnd,NULL,TRUE);//刷新窗口,会触发WM_PAINT break; case ID_32797://画笔样式 g_nPenWdith = 5; InvalidateRect(hWnd,NULL,TRUE);//刷新窗口,会触发WM_PAINT break; case ID_32799://画刷颜色 g_nBrushColor = RGB(255,0,0); InvalidateRect(hWnd,NULL,TRUE);//刷新窗口,会触发WM_PAINT break; case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: DefWindowProc(hWnd, message, wParam, lParam); break; } } //点的绘制 void DrawPixel(HDC hDC) { COLORREF nColor = RGB(255,0,0); /* *绘制: COLORREF SetPixel( * HDC hdc, //DC句柄 * int X, //x坐标 * int Y, //y坐标 * COLORREF crColor ); // 点的颜色 */ SetPixel(hDC,100,100,nColor); } void GetPixelColor(HDC hDC) { DrawPixel(hDC); /*获取点的颜色 *获取: COLORREF GetPixel( * HDC hdc, //DC句柄 * int XPos, //x坐标 * int nYPos ); //y坐标 * 返回指定坐标位置的点的颜色 */ COLORREF nColor = GetPixel( hDC, 100, 100 ); //获取颜色的三色值 int nRed = GetRValue( nColor ); int nGreen = GetGValue( nColor ); int nBlue = GetBValue( nColor ); CHAR szText[260] = { 0 }; sprintf_s( szText, "COLOR=%08X, RED=%d GREEN=%d BLUE=%d", nColor, nRed, nGreen, nBlue ); MessageBox( NULL, szText, "GetPixelColor", MB_OK ); } //绘制直线 void DrawLine( HDC hDC ) { MoveToEx( hDC, 0, 0, NULL ); LineTo( hDC, 500, 500 ); MoveToEx( hDC, 500, 0, NULL ); LineTo( hDC, 0, 500 ); } //绘制圆弧 void DrawArc(HDC hDC ) { //逆时针的方式 SetArcDirection( hDC, AD_COUNTERCLOCKWISE ); //通过外切矩形和切割线 /*BOOL Arc( HDC hdc, * int nLeftRect, // 外切矩形的坐标 * int nTopRect,//外切矩形的坐标 * int nRightRect,//外切矩形的坐标 * int nBottomRect,//外切矩形的坐标 * int nXStartArc,//起始切割半径的X坐标 * int nYStartArc,//起始切割半径的Y坐标 * int nXEndArc, //终止切割半径的X坐标 * int nYEndArc ); //终止切割半径的X坐标 * 可以使用SetArcDirection函数,设置Arc函数 * 切割方向:顺时针和逆时针 */ Arc( hDC, 400, 200, 500, 300,500, 200, 400, 200); //顺时针的方式 SetArcDirection( hDC, AD_CLOCKWISE ); Arc( hDC, 500, 200, 600, 300,600, 200, 500, 200); /*没有这个话会出现0,0 到200,200 的一条直线*/ MoveToEx( hDC, 200, 200, NULL ); /* 另一种绘制圆的方法, *BOOL AngleArc( * HDC hdc, // handle to device context * int X, //圆心的X坐标 * int Y, //圆心的Y坐标 * DWORD dwRadius,//圆的半径 * FLOAT eStartAngle,//开始角度 * FLOAT eSweepAngle );//夹角 */ AngleArc(hDC,200,200,100,60,120); LineTo( hDC, 200, 200 ); } //绘制折线 void DrawPolyLine(HDC hDC) { POINT ptPolyLine[7] = { 0 }; ptPolyLine[0].x = 100; ptPolyLine[0].y = 100; ptPolyLine[1].x = 200; ptPolyLine[1].y = 100; ptPolyLine[2].x = 200; ptPolyLine[2].y = 200; ptPolyLine[3].x = 300; ptPolyLine[3].y = 200; ptPolyLine[4].x = 300; ptPolyLine[4].y = 300; ptPolyLine[5].x = 400; ptPolyLine[5].y = 300; ptPolyLine[6].x = 400; ptPolyLine[6].y = 400; /* *BOOL Polyline( * HDC hdc, //DC句柄 * CONST POINT *lppt,//Polyline顶点的坐标数组 * int cPoints ); //顶点数组的长度 * PolylineTo 与Polyline类似, 只是在绘制Polyline前 * ,从当前点使用LineTo绘制直线到Polyline的第一个顶点 */ Polyline( hDC, ptPolyLine, 7 ); //PolylineTo( hDC, ptPolyLine, 3 ); /* *绘制多组折线 PolyPolyline * BOOL PolyPolyline( HDC hdc, * CONST POINT *lppt,//所有点的数组 * CONST DWORD *lpdwPolyPoints,//每组点的数量 * DWORD cCount );//分组的数量 */ //DWORD nGroup[] = { 4, 3 }; //PolyPolyline( hDC, ptPolyLine,nGroup, 2 ); } void DrawBizer( HDC hDC ) { POINT ptBizer[7] = { 0 }; ptBizer[0].x = 100; //端点 ptBizer[0].y = 100; // ptBizer[1].x = 100; //控制点 ptBizer[1].y = 50; // ptBizer[2].x = 300; //控制点 ptBizer[2].y = 150; // ptBizer[3].x = 300; //端点 ptBizer[3].y = 100; // ptBizer[4].x = 300; //控制点 ptBizer[4].y = 400; ptBizer[5].x = 400; //控制点 ptBizer[5].y = 200; ptBizer[6].x = 500; //端点 ptBizer[6].y = 300; /* Bezier曲线 BOOL PolyBezier(HDC hdc, CONST POINT *lppt,//点数组,最少4个点 DWORD cPoints );//点的数量 4个点: 1和4是端点,2.3点是控制点 7个点: 1.4.7是端点,其余是控制点 */ PolyBezier( hDC, ptBizer, 7 ); MoveToEx( hDC, ptBizer[0].x, ptBizer[0].y, NULL ); LineTo( hDC, ptBizer[1].x, ptBizer[1].y ); MoveToEx( hDC, ptBizer[3].x, ptBizer[3].y, NULL ); LineTo( hDC, ptBizer[2].x, ptBizer[2].y ); } //多样式线 void DrawPolyDraw( HDC hDC ) { POINT ptDraw[4] = { 0 }; ptDraw[0].x = 100; ptDraw[0].y = 100; ptDraw[1].x = 200; ptDraw[1].y = 100; ptDraw[2].x = 200; ptDraw[2].y = 200; ptDraw[3].x = 300; ptDraw[3].y = 200; BYTE ptType[4] = {0}; ptType[0] = PT_MOVETO; ptType[1] = PT_LINETO; ptType[2] = PT_LINETO; ptType[3] = PT_LINETO; /* * BOOL PolyDraw( HDC hdc, * CONST POINT *lppt,//各个点的数组 * CONST BYTE *lpbTypes, //从某点到下一点的绘制方式 pointer to line and curve identifiers * int cCount); //点的数量 * * lpbTypes - PT_MOVETO 移动到该点 * PT_LINETO 绘直线 * PT_BIZERTO Biezer曲线 */ PolyDraw( hDC, ptDraw, ptType, 4 ); } void DrawRect( HDC hDC ) { //矩形 Rectangle( hDC, 100, 100, 200, 200 ); //带圆角矩形 /* 带圆角的矩形 BOOL RoundRect( HDC hdc, int nLeftRect, //左上X坐标 int nTopRect, //左上Y坐标 int nRightRect,//右下X坐标 int nBottomRect, //右下Y坐标 int nWidth, //生成圆角的椭圆的宽度 int nHeight );//生成圆角的椭圆的高度 */ RoundRect( hDC, 300, 100, 400, 200, 50, 50 ); } void DrawEllipse( HDC hDC ) { //圆 /* BOOL Ellipse( HDC hdc, int nLeftRect, //外切矩形左上X坐标 int nTopRect,//外切矩形左上Y坐标 int nRightRect, //外切矩形右下X坐标 int nBottomRect); //外切矩形右下Y坐标 */ Ellipse( hDC, 100, 100, 200, 200 ); //椭圆 Ellipse( hDC, 300, 100, 500, 200 ); } void DrawPie( HDC hDC ) { Pie( hDC, 100, 100, 500, 400, 500, 100, 100, 100 ); } void DrawChord( HDC hDC ) { /* 弦 * BOOL Chord( HDC hdc, * int nLeftRect, //外切矩形左上X坐标 * int nTopRect, //外切矩形左上Y坐标 * int nRightRect, //外切矩形右下X坐标 * int nBottomRect, //外切矩形右下Y坐标 * int nXRadial1,//切割起始半径X坐标 * int nYRadial1,//切割起始半径Y坐标 * int nXRadial2,//切割终止半径X坐标 * int nYRadial2 );//切割终止半径Y坐标 */ Chord( hDC, 100, 100, 500, 400, 500, 100, 100, 100 ); } void DrawPloygon( HDC hDC ) { POINT ptPloygon[4] = { 0 }; ptPloygon[0].x = 100; ptPloygon[0].y = 100; ptPloygon[1].x = 200; ptPloygon[1].y = 100; ptPloygon[3].x = 600; ptPloygon[3].y = 300; ptPloygon[2].x = 500; ptPloygon[2].y = 300; /* 多边形 * BOOL Polygon( HDC hdc, * CONST POINT *lpPoints, //多边形的顶点 * int nCount ); //顶点的数量 * PolyPolygon 可以绘制多组多边形 */ Polygon( hDC, ptPloygon, 4 ); } void OnPaint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hWnd,&ps); /*创建画笔 * HPEN CreatePen( * int fnPenStyle, //画笔的样式 * int nWidth, //画笔的宽度 * COLORREF crColor);//画笔的颜色 */ HPEN hPen = CreatePen(g_nPenStyle,g_nPenWdith,g_nPenColor); /*设置画笔到当前DC * HGDIOBJ SelectObject( * HDC hdc, // 当前DC的句柄 * HGDIOBJ hgdiobj );//要使用的GDI对象句柄 * 返回当前DC原来使用的同类型的GDI对象句柄。 */ HPEN hOldPen = (HPEN)SelectObject(hDC,hPen); //创建画刷,画刷只对填充物有效果,圆,多边形,矩形等 HBRUSH hBrush = CreateSolidBrush(g_nBrushColor); //设置画刷到当前DC HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC,hBrush); // 根据不同的绘制类型,来做不同的指令 switch(g_nDrawType){ case ID_32774://绘制点 DrawPixel(hDC); break; case ID_32775://获取点颜色 GetPixelColor(hDC); break; case ID_32772://绘制直线 DrawLine(hDC); break; case ID_32776://绘制圆弧 DrawArc(hDC); break; case ID_32777://绘制折线 DrawPolyLine(hDC); break; case ID_32780://绘制曲线 DrawBizer( hDC ); break; case ID_32781://绘制多样式曲线 DrawPolyDraw( hDC ); break; case ID_32782://绘制矩形 DrawRect( hDC ); break; case ID_32783://绘制圆和椭圆 DrawEllipse( hDC ); break; case ID_32785://绘制饼丝 DrawPie( hDC ); break; case ID_32786://绘制炫 DrawChord( hDC ); break; case ID_32787://绘制多边形 DrawPloygon( hDC ); break; default: break; } //取出画刷 SelectObject( hDC, hOldBrush ); //删除画刷 DeleteObject( hBrush ); //取出画笔,旧画笔放进去,新画笔就会释放 SelectObject( hDC, hOldPen ); //销毁画笔 DeleteObject( hPen ); EndPaint(hWnd,&ps); } // // 函数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目的: 处理主窗口的消息。 // // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND:/*菜单的信息处理*/ OnCommand(hWnd,message,wParam,lParam); #if 0 wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } #endif break; case WM_PAINT: /*绘图指令*/ OnPaint(hWnd, message, wParam, lParam); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // “关于”框的消息处理程序。 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; }