您的位置:首页 > 其它

Windows学习心得【数字时钟】

2014-04-16 20:32 281 查看
#include<windows.h>

#define ID_TIMER 1

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

int WINAPI WinMain(HINSTANCE hInstance,//应用程序当前实例的句柄
HINSTANCE hPREVInstance,//应用程序先前的实例句柄
PSTR szCmdLine,//指向应用程序命令行的字符串的指针
int iCmdShow)//指明窗口如何显示
{
static TCHAR szAppName[]=TEXT("DigClock");
HWND hwnd;//当前实例的句柄
MSG msg;//消息
WNDCLASS wndclass;//类名

wndclass.style=CS_HREDRAW | CS_VREDRAW;//窗口的显示方式,此处为水平重画和竖直重画
wndclass.cbClsExtra=0;//窗口扩展,此处为0
wndclass.cbWndExtra=0;//窗口实例扩展,此处为0
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);//窗口背景颜色的设置,此处设置为白色
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);//鼠标的显示方式,此处设置为标准型
wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);//窗口的显示方式,此处设置为应用程序型
wndclass.hInstance=hInstance;//窗口的实例句柄
wndclass.lpfnWndProc=WndProc;//窗口回调函数
wndclass.lpszClassName=szAppName;//窗口类名
wndclass.lpszMenuName=NULL;//窗口菜单,此处没菜单设为NULL

if(!RegisterClass(&wndclass))//注册窗口,若注册失败,产生如下的信息
{
MessageBox(NULL,TEXT("Program requires Windows NT!"),
szAppName,MB_ICONERROR);
return 0;
}

////创建窗口,如果函数成功,返回值为新窗口的句柄:如果函数失败,返回值为NULL。
hwnd=CreateWindow(szAppName,
TEXT("Digital 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 DisplayDigit(HDC hdc,int iNumber)
{
//这个数组是用来根据程序需要显示那个数字
//进而判断要显示的数字是哪一个的
static BOOL fSevenSegment[10][7]={
1,1,1,0,1,1,1,				//0
0,0,1,0,0,1,0,				//1
1,0,1,1,1,0,1,				//2
1,0,1,1,0,1,1,				//3
0,1,1,1,0,1,0,				//4
1,1,0,1,0,1,1,				//5
1,1,0,1,1,1,1,				//6
1,0,1,0,0,1,0,				//7
1,1,1,1,1,1,1,				//8
1,1,1,1,0,1,1};				//9

static POINT ptSegment[7][6]={
//这个数组是用来表示组成每一个数字的六边形的每个顶点的坐标
7,  6,  11,  2,  31,  2,  35,  6,  31, 10,  11, 10,
6,  7,  10, 11,  10, 31,   6, 35,   2, 31,   2, 11,
36,  7,  40, 11,  40, 31,  36, 35,  32, 31,  32, 11,
7, 36,  11, 32,  31, 32,  35, 36,  31, 40,  11, 40,
6, 37,  10, 41,  10, 61,   6, 65,   2, 61,   2, 41,
36, 37,  40, 41,  40, 61,  36, 65,  32, 61,  32, 41,
7, 66,  11, 62,  31, 62,  35, 66,  31, 70,  11, 70 };

int iSeg;

//每个数字最多有七个六边形,要进行遍历,通过fSevenSegment来判断是否显示
//比如说5,系统要考虑哪些六边形能够组成5这个数字
//然后那这些符合要求的六边形一个一个输出到指定的位置
for(iSeg=0;iSeg<7;iSeg++)
if(fSevenSegment[iNumber][iSeg])
Polygon(hdc,ptSegment[iSeg],6);
//Polygon该函数画一个由直线相连的两个以上顶点组成的多边形,用当前画笔画多边形轮廓,用当前画刷和多边形填充模式填充多边形。
//HDC:设备环境句柄
//第二个参数为指向用于指定多边形顶点的POINT结构数组的指针。坐标以当前位置为原点
//第三个参数为多边形的遍数
}

void DisplayTwoDigits(HDC hdc,int iNumber,BOOL fSuppress)
{
//fSuppress这个参数的作用为显示小时时,小时的第一位如果是0则不显示
//具体的逻辑实现,读者可以自己揣摩一下
if(!fSuppress || (iNumber/10!=0))
DisplayDigit(hdc,iNumber/10);

//画完第一个数字后,要把画图区域向后移一个数字的单位宽(42)
//OffsetWindowOrgEx函数用指定的水平位移和垂直位移改变设备环境的窗口原点
//hdc:指向设备环境的句柄
//第二个参数为指定以逻辑单位为单位的水平位移即一次移动多少个单位宽
//第三个参数为指定以逻辑单位为单位的垂直位移
//第四个参数为指向POINT结构的指针,先前原点的逻辑坐标存放在此结构中,如果是NULL,那么先前原点没有被返回

OffsetWindowOrgEx(hdc,-42,0,NULL);

//对于时分秒来说,画完第一个数字后再次调用DisplayDigit函数来画第二个数字
DisplayDigit(hdc,iNumber%10);
//然后再把画图区域右移一个数字的单位宽
OffsetWindowOrgEx(hdc,-42,0,NULL);
}

void DisplayColon(HDC hdc)//此函数为画数字之间的冒号
{
POINT ptColon[2][4]={
//定义了每个方框的四个顶点的点结构体
2,21,6,17,10,21,6,25,
2,51,6,47,10,51,6,55};

//依次画出两个四边形
Polygon(hdc,ptColon[0],4);
Polygon(hdc,ptColon[1],4);

OffsetWindowOrgEx(hdc,-12,0,NULL);
//画完后,画图区域向后移动一个冒号的宽度(12)
}

void DisplayTime(HDC hdc,BOOL f24Hour,BOOL fSuppress)
{
SYSTEMTIME st;//定义了一个时间结构体

GetLocalTime(&st);//提取系统的当前时间

if(f24Hour)//按照24小时制进行绘画
DisplayTwoDigits(hdc,st.wHour,fSuppress);
else//按照12小时制进行绘画
DisplayTwoDigits(hdc,(st.wHour%=12)?st.wHour:12,fSuppress);

DisplayColon(hdc);//画出冒号

DisplayTwoDigits(hdc,st.wMinute,FALSE);//画出分

DisplayColon(hdc);//画出冒号

DisplayTwoDigits(hdc,st.wSecond,FALSE);//画出秒
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)//回调函数
{
static BOOL f24Hour,fSuppress;
static HBRUSH hBrushRed;//定义了一个画刷结构体
static int cxClient,cyClient;
HDC hdc;//句柄
PAINTSTRUCT ps;//该结构体包含了某应用程序用来绘制它所拥有的窗口客户区所需要的信息
TCHAR szBuffer[2];

switch(message)
{
case WM_CREATE:
hBrushRed=CreateSolidBrush(RGB(255,0,0));//创建一个和红色画刷
//SetTimer创建或设置一个定时器
//如果函数成功,hWnd参数为非0,则返回一个非零的整数,可以把这个非零的整数传递给KillTimer来销毁时钟.
//hwnd是一个窗口句柄,它指向接收WM_TIMER消息的窗口过程
//第二个参数是一个计时器的ID,它不能为0
//第三个参数是一个32位的无符号整数,它指定以毫秒为单位的时间间隔
//第四个参数一般为NULL,系统将会向消息队列中放入一个WM_TIMER消息,
SetTimer (hwnd,ID_TIMER,1000,NULL);
case WM_SETTINGCHANGE:
//GetLocaleInfo获取系统一些信息
//LOCALE_USER_DEFAULT默认用户语言环境
//LOCALE_ITIME表示要提取系统时间信息
//szBuffer用来接收系统数据
//2为szBuffer的大小
GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_ITIME,szBuffer,2);
//如果szBuffer == "0"表示12小时制,szBuffer == "1"表示24小时制
f24Hour=(szBuffer[0]=='1');

GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_ITLZERO,szBuffer,2);

fSuppress=(szBuffer[0]=='0');//0 表示不为0开头  1表示是0开头

InvalidateRect(hwnd,NULL,TRUE);//刷新区域
return 0;
case WM_SIZE:
cxClient=LOWORD(lParam);
cyClient=HIWORD(lParam);
return 0;
case WM_TIMER:
InvalidateRect(hwnd,NULL,TRUE);//每一秒刷新一次
return 0;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);//获取句柄

SetMapMode(hdc,MM_ISOTROPIC);
//SetMapMode函数设置指定设备环境的映射方式,映射方式定义了将逻辑单位转换为设备单位的度量单位,并定义了设备的X、Y轴的方向
//逻辑单位转换成具有均等比例轴的任意单位,即沿X轴的一个单位等于沿Y轴的一个单位

SetWindowExtEx(hdc,276,72,NULL);
//用指定的值来设置指定设备环境坐标的X轴、Y轴范围

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

SetWindowOrgEx(hdc,138,36,NULL);
//该函数用指定的坐标设置设备环境的窗口原点

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

SelectObject(hdc,GetStockObject(NULL_PEN));
//该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象。
SelectObject(hdc,hBrushRed);

DisplayTime(hdc,f24Hour,fSuppress);//显示时间

EndPaint(hwnd,&ps);//释放句柄
return 0;
case WM_DESTROY:
KillTimer(hwnd,ID_TIMER);//移除定时器函数的声明:移除先前用SetTimer设置的定时器。

DeleteObject(hBrushRed);//还原画刷
PostQuitMessage(0);//该函数向系统表明有个线程有终止请求。通常用来响应WM_DESTROY消息
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);//该函数调用缺省的窗口过程来为应用程序没有处理的任何窗口消息提供缺省的处理
}
这部分代码的逻辑难度我觉得要比前几章大一些,我还是有一些不太懂得地方,特别是WM_PAINT里面的那几句代码,特别迷惑不知道到底是起什么作用的。下面传张图纪念一下这有意思的数字时钟
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: