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