要制作一个有用的数字时钟,首先要得获得系统的时间,然后把小时,分钟,秒分离出来,然后用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映射博客。实现客户区内容随着屏幕的大小自动伸缩。