计时器(2)之数字时钟

要制作一个有用的数字时钟,首先要得获得系统的时间,然后把小时,分钟,秒分离出来,然后用Polygon画图,然后使用TIMER计时器,每秒显示一起,这里为了好看设置了“七段译码器”,其实,这个跟单片机的数码管时钟显示,几乎是一样的。

下面我们先看看怎么样才能获得当前时间,先看SYSTEMTIME结构的参数

typedef struct _SYSTEMTIME { 
    WORD wYear; 
    WORD wMonth; 
    WORD wDayOfWeek; 
    WORD wDay; 
    WORD wHour; 
    WORD wMinute; 
    WORD wSecond; 
    WORD wMilliseconds; 
} SYSTEMTIME, *PSYSTEMTIME


参数的意思一目了然。

//使用GetLocaltime(&st)可以获取实例化的SYSTEMTIME对象


下面看看一段完整的程序,一个数字时钟

#include<windows.h>
#include<windowsx.h>
#define ID_TIMER 1

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);

int WINAPI WinMain(
  HINSTANCE hInstance,      // handle to current instance
  HINSTANCE hPrevInstance,  // handle to previous instance
  LPSTR lpCmdLine,          // command line
  int nCmdShow              // show state
)
{
	static TCHAR szAppName[]=TEXT("leidemingzi");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;
	
	wndclass.cbClsExtra=0;
	wndclass.cbWndExtra=0;
	wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
	wndclass.hIcon=LoadIcon(NULL,IDI_ERROR);
	wndclass.hInstance=hInstance;
	wndclass.lpfnWndProc=WindowProc;
	wndclass.lpszClassName=szAppName;
	wndclass.lpszMenuName=NULL;
	wndclass.style=CS_HREDRAW|CS_VREDRAW;
	
	if(!RegisterClass(&wndclass))
	{
		MessageBox(NULL,TEXT("the program require windows NT"),TEXT("tips"),MB_ICONERROR);
		return 0;
	}

	hwnd=CreateWindow(
	  szAppName,  // registered class name
	  TEXT("this is title"), // window name
	  WS_OVERLAPPEDWINDOW,        // window style
	  CW_USEDEFAULT,                // horizontal position of window
	  CW_USEDEFAULT,                // vertical position of window
	  CW_USEDEFAULT,           // window width
	  CW_USEDEFAULT,          // window height
	  NULL,      // handle to parent or owner window
	  NULL,          // menu handle or child identifier
	  hInstance,  // handle to application instance
	  NULL        // window-creation data
);

	ShowWindow(hwnd,nCmdShow);
	UpdateWindow(hwnd);

	while(GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

void DisplayDigit(HDC hdc,int iNumber)
{
	static BOOL fSevenSegment[10][7]=//十个数字,当对应的位为1时,显示
	{
		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] = //一个小菱形由6个点构成,一个点由(x,y)组成
	{
        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;
	for(iSeg=0;iSeg<7;++iSeg)
		if(fSevenSegment[iNumber][iSeg])
			Polygon(hdc,ptSegment[iSeg],6);
}

void DisplayTwoDigits(HDC hdc,int iNumber,BOOL fSuppress)
{
	if(!fSuppress||(iNumber/10)!=0)
	{
		DisplayDigit(hdc,iNumber/10);
	}
	
	OffsetWindowOrgEx(hdc,-42,0,NULL);//向右移动42PX,以便写后一个数字
	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);
}

void DisplayTime(HDC hdc,BOOL f24Hour,BOOL fSuppress)
{
	SYSTEMTIME st;
	GetLocalTime(&st);//获取系统时间结构体

	if(f24Hour)
		DisplayTwoDigits(hdc,st.wHour,fSuppress);
	else
		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 WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
	static BOOL f24Hour,fSuppress;
	static HBRUSH hbrush;
	static int cxClient,cyClient;
	HDC hdc;
	PAINTSTRUCT ps;
	TCHAR szBuffer[2];

	switch(uMsg)
	{
	case WM_CREATE:
		hbrush=CreateSolidBrush(RGB(255,0,0));
		SetTimer(hwnd,ID_TIMER,1000,NULL);
	

	case WM_SETTINGCHANGE://当有更该的时候,判断是用12时制还是24时制
		GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_ITIME,szBuffer,2);
		f24Hour=(szBuffer[0]=='1');

		GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_ITLZERO,szBuffer,2);
		fSuppress=(szBuffer[1]=='0');

		InvalidateRect(hwnd,NULL,TRUE);
		return 0;

	case WM_SIZE:
		cxClient=GET_X_LPARAM(lParam);//获取客户端长宽
		cyClient=GET_Y_LPARAM(lParam);
		return 0;

	case WM_TIMER:
		InvalidateRect(hwnd,NULL,TRUE);
		return 0;

	case WM_PAINT:
		hdc=BeginPaint(hwnd,&ps);
		
		SetMapMode(hdc,MM_ISOTROPIC);//GDI映射模式
		SetWindowExtEx(hdc,276,72,NULL);
		SetViewportExtEx(hdc,cxClient,cyClient,NULL);

		SetWindowOrgEx(hdc,138,36,NULL);
		SetViewportOrgEx(hdc,cxClient/2,cyClient/2,NULL);
		
		SelectObject(hdc,GetStockObject(NULL_PEN));//不需要边框
		SelectObject(hdc,hbrush);

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

		EndPaint(hwnd,&ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

看看效果图:

如果对其中的GDI映射不是很明白,可以看我前面写的一篇GDI映射博客。实现客户区内容随着屏幕的大小自动伸缩。

你可能感兴趣的:(计时器(2)之数字时钟)