爱悠闲 > Windows学习心得【模拟时钟】

Windows学习心得【模拟时钟】

分类: Windows学习日记  |  标签: winapi,windows,源码,应用程序,图片  |  作者: u013517637 相关  |  发布日期 : 2015-06-02  |  热度 : 1340°
#include <windows.h>
#include <math.h>

#define ID_TIMER    1
#define TWOPI       (2 * 3.14159)

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;//首先是一个回调函数的声明

int WINAPI WinMain (HINSTANCE hInstance, //应用程序当前实例的句柄
					HINSTANCE hPrevInstance,//应用程序先前的实例句柄
                    PSTR szCmdLine, //指向应用程序命令行的字符串的指针  
					int iCmdShow)//指明窗口如何显示
{
     static TCHAR szAppName[] = TEXT ("Clock") ;
     HWND         hwnd;//当前实例的句柄
     MSG          msg;//消息
     WNDCLASS     wndclass ;//类名 
     
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;//窗口的显示方式,此处为水平重画和竖直重画
     wndclass.lpfnWndProc   = WndProc ;//窗口回调函数
     wndclass.cbClsExtra    = 0 ;//窗口扩展,此处为0
     wndclass.cbWndExtra    = 0 ;//窗口实例扩展,此处为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 ;//窗口菜单,此处没菜单设为NULL  
     wndclass.lpszClassName = szAppName ;//窗口类名
     
     if (!RegisterClass (&wndclass))//注册窗口,若注册失败,产生如下的信息  
     {
          MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }


     ////创建窗口,如果函数成功,返回值为新窗口的句柄:如果函数失败,返回值为NULL。
     hwnd = CreateWindow (szAppName, 
						TEXT ("Analog Clock"),//窗口的名字
                          WS_OVERLAPPEDWINDOW,//指定创建窗口的风格 
                          CW_USEDEFAULT,//指定窗口的初始水平位置,如果该参数被设为CW_USEDEFAULT则系统为窗口选择缺省的左上角坐标并忽略Y参数
						  CW_USEDEFAULT,//指定窗口的初始垂直位置 
                          CW_USEDEFAULT, //以设备单元指明窗口的宽度。若是CW_USEDEFAULT,则系统为窗口选择一个缺省的宽度
						  CW_USEDEFAULT,//以设备单元指明窗口的高度。若被设为CW_USEDEFAULT,则系统忽略nHeight参数。
                          NULL,//指向被创建窗口的父窗口或所有者窗口的句柄,此处为NULL  
						  NULL, //菜单句柄,或依据窗口风格指明一个子窗口标识,此处为NULL 
						  hInstance, //与窗口相关联的模块实例的句柄
						  NULL) ;//指向一个值的指针,该值传递给窗口WM_CREATE消息
     
     ShowWindow (hwnd, iCmdShow) ;//显示窗口,hWnd:指窗口句柄。iCmdShow:指定窗口如何显示
     UpdateWindow (hwnd) ;//更新窗口,hWnd:指窗口句柄
     
     while (GetMessage (&msg, NULL, 0, 0))//消息循环
     {
          TranslateMessage (&msg) ;//该函数将虚拟键消息转换为字符消息
          DispatchMessage (&msg) ;//该函数分发一个消息给窗口程序
     }
     return msg.wParam ;//wParam是消息携带的参数,可以是个值,也可以是个地址
}

void SetIsotropic (HDC hdc, int cxClient, int cyClient)
{
     SetMapMode (hdc, MM_ISOTROPIC) ;
	 //SetMapMode函数设置指定设备环境的映射方式,映射方式定义了将逻辑单位转换为设备单位的度量单位,并定义了设备的X、Y轴的方向  
       //逻辑单位转换成具有均等比例轴的任意单位,即沿X轴的一个单位等于沿Y轴的一个单位  
     SetWindowExtEx (hdc, 1000, 1000, NULL) ;
     //用指定的值来设置指定设备环境坐标的X轴、Y轴范围

     SetViewportExtEx (hdc, cxClient / 2, -cyClient / 2, NULL) ;
	 //设置设备环境的窗口原点

     SetViewportOrgEx (hdc, cxClient / 2,  cyClient / 2, NULL) ;
	 //SetViewportOrgEx说明哪个设备点映射到窗口原点 
}

void RotatePoint (POINT pt[], int iNum, int iAngle)
{
	//pt是含有一个或多个点的数组,iNum为点的数目,iAngle为每个点的旋转角度
     int   i ;
     POINT ptTemp ;//定义一个点的结构体
     
     for (i = 0 ; i < iNum ; i++)
     {
          ptTemp.x = (int) (pt[i].x * cos (TWOPI * iAngle / 360) +
               pt[i].y * sin (TWOPI * iAngle / 360)) ;//转换成旋转后的x坐标
          
          ptTemp.y = (int) (pt[i].y * cos (TWOPI * iAngle / 360) -
               pt[i].x * sin (TWOPI * iAngle / 360)) ;//转换成旋转后的y坐标
          
          pt[i] = ptTemp ;//新的点结构体替换原来的点结构体
     }
}

void DrawClock (HDC hdc)//用来画出时钟周围的点
{
     int   iAngle ;
     POINT pt[3] ;
     
     for (iAngle = 0 ; iAngle < 360 ; iAngle += 6)
     {
          pt[0].x =   0 ;
          pt[0].y = 900 ;
          
          RotatePoint (pt, 1, iAngle) ;//用来设计旋转后的点的坐标信息
          
          pt[2].x = pt[2].y = iAngle % 5 ? 33 : 100 ;//判断钟表周围的点的直径大小
          
          pt[0].x -= pt[2].x / 2 ;
          pt[0].y -= pt[2].y / 2 ;//获取钟表周围点的外围矩形的左上角坐标值
          
          pt[1].x  = pt[0].x + pt[2].x ;
          pt[1].y  = pt[0].y + pt[2].y ;//获取钟表周围点的外围矩形的右下角坐标值
          
          SelectObject (hdc, GetStockObject (BLACK_BRUSH)) ;//设置句柄
          
          Ellipse (hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y) ;
		  //描绘一个椭圆,由指定的矩形围绕。椭圆用当前选择的画笔描绘,并用当前选择的刷子填充
     }
}

void DrawHands (HDC hdc, SYSTEMTIME * pst, BOOL fChange)
//此函数用来绘画时针,分针和秒针
{

     static POINT pt[3][5] = { 0, -150, 100, 0, 0, 600, -100, 0, 0, -150,//时针的五个点的坐标
                               0, -200,  50, 0, 0, 800,  -50, 0, 0, -200,//分钟的五个点的坐标
                               0,    0,   0, 0, 0,   0,    0, 0, 0,  800 } ;//秒针的五个点的坐标
     int          i, iAngle[3] ;
     POINT        ptTemp[3][5] ;
     
     iAngle[0] = (pst->wHour * 30) % 360 + pst->wMinute / 2 ;//用来获取当前时间时针顺时针偏离竖直方向的角度
     iAngle[1] =  pst->wMinute  *  6 ;//用来获取当前时间分针顺时针偏离竖直方向的角度
     iAngle[2] =  pst->wSecond  *  6 ;//用来获取当前时间秒针顺时针偏离竖直方向的角度
     
     memcpy (ptTemp, pt, sizeof (pt)) ;//把pt的信息拷贝到ptTemp中
     
     for (i = fChange ? 0 : 2 ; i < 3 ; i++)//fChange的作用就是当为真时,重绘时针分针和秒针
     {
          RotatePoint (ptTemp[i], 5, iAngle[i]) ;
          
          Polyline (hdc, ptTemp[i], 5) ;
     }
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static int        cxClient, cyClient ;
     static SYSTEMTIME stPrevious ;
     BOOL              fChange ;
     HDC               hdc ;//句柄
     PAINTSTRUCT       ps ;//该结构体包含了某应用程序用来绘制它所拥有的窗口客户区所需要的信息
     SYSTEMTIME        st ;//定义了一个时间结构体 
          
     switch (message)
     {
     case WM_CREATE :
          SetTimer (hwnd, ID_TIMER, 1000, NULL) ;
		  //SetTimer创建或设置一个定时器  
		  //如果函数成功,hWnd参数为非0,则返回一个非零的整数,可以把这个非零的整数传递给KillTimer来销毁时钟.    
          //hwnd是一个窗口句柄,它指向接收WM_TIMER消息的窗口过程    
          //第二个参数是一个计时器的ID,它不能为0    
          //第三个参数是一个32位的无符号整数,它指定以毫秒为单位的时间间隔    
          //第四个参数一般为NULL,系统将会向消息队列中放入一个WM_TIMER消息, 
          GetLocalTime (&st) ;//取本地时间
          stPrevious = st ;
          return 0 ;
          
     case WM_SIZE :
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;
          return 0 ;
          
     case WM_TIMER :
          GetLocalTime (&st) ;//取本地时间
                    
          fChange = st.wHour   != stPrevious.wHour ||
                    st.wMinute != stPrevious.wMinute ;
		  //判断什么时候需要重绘时针和分针
          
          hdc = GetDC (hwnd) ;//获取环境句柄
          
          SetIsotropic (hdc, cxClient, cyClient) ;//设置映射方式
          
          SelectObject (hdc, GetStockObject (WHITE_PEN)) ;//设置画刷

          DrawHands (hdc, &stPrevious, fChange) ;//此函数用来绘画时针,分针和秒针
          
          SelectObject (hdc, GetStockObject (BLACK_PEN)) ;//设置画刷

          DrawHands (hdc, &st, TRUE) ;//此函数用来绘画时针,分针和秒针
          
          ReleaseDC (hwnd, hdc) ;//释放句柄
          
          stPrevious = st ;
          return 0 ;
          
     case WM_PAINT :
          hdc = BeginPaint (hwnd, &ps) ;//获取句柄
          
          SetIsotropic (hdc, cxClient, cyClient) ;//设置映射方式
          DrawClock    (hdc) ;//画出时钟周围的点
          DrawHands    (hdc, &stPrevious, TRUE) ;//画出时针分针和秒针
          
          EndPaint (hwnd, &ps) ;//释放句柄
          return 0 ;
          
     case WM_DESTROY :
          KillTimer (hwnd, ID_TIMER) ;
		  //移除定时器函数的声明:移除先前用SetTimer设置的定时器

          PostQuitMessage (0) ;//该函数向系统表明有个线程有终止请求。通常用来响应WM_DESTROY消息
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;//该函数向系统表明有个线程有终止请求。通常用来响应WM_DESTROY消息
}

下面是程序运行的图片 

在电脑前一直盯了将近6个小时,真是累啊,回去洗个澡,明天还得上高数呐。。。。加油,加油!!!!!