首页 > 代码库 > 走进windows编程的世界-----绘图相关

走进windows编程的世界-----绘图相关

 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;
}